From 0f0fa556772922cb83930bc16fae2b8ec280768e Mon Sep 17 00:00:00 2001 From: sveinungf Date: Mon, 25 Dec 2023 15:10:00 +0100 Subject: [PATCH 01/30] WIP for a string interpolation handler for SpreadsheetBuffer --- SpreadCheetah/SpreadsheetBuffer.cs | 101 +++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index 9096c183..9d93fa5c 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -1,4 +1,8 @@ using SpreadCheetah.Helpers; +using System.Buffers.Text; +using System.Diagnostics; +using System.Globalization; +using System.Runtime.CompilerServices; namespace SpreadCheetah; @@ -38,4 +42,101 @@ public ValueTask FlushToStreamAsync(Stream stream, CancellationToken token) return stream.WriteAsync(_buffer.AsMemory(0, index), token); #endif } + + public bool TryWrite([InterpolatedStringHandlerArgument("")] ref TryWriteInterpolatedStringHandler handler) + { + return handler._success; + } + + [InterpolatedStringHandler] + public ref struct TryWriteInterpolatedStringHandler + { + private readonly SpreadsheetBuffer _buffer; + internal bool _success; + + public TryWriteInterpolatedStringHandler(int literalLength, int formattedCount, SpreadsheetBuffer buffer, out bool shouldAppend) + { + _ = formattedCount; + _buffer = buffer; + _success = shouldAppend = buffer.FreeCapacity >= literalLength; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool AppendLiteral(string value) + { + if (value is not null) + { + var dest = _buffer.GetSpan(); +#if NET8_0_OR_GREATER + if (System.Text.Unicode.Utf8.TryWrite(dest, CultureInfo.InvariantCulture, $"{value}", out var bytesWritten)) +#else + if (Utf8Helper.TryGetBytes(value, dest, out var bytesWritten)) +#endif + { + _buffer.Advance(bytesWritten); + return true; + } + } + + return Fail(); + } + + public bool AppendFormatted(int value) + { + if (Utf8Formatter.TryFormat(value, _buffer.GetSpan(), out var bytesWritten)) + { + _buffer.Advance(bytesWritten); + return true; + } + + return Fail(); + } + + public bool AppendFormatted(T value) + { + Debug.Fail("Create non-generic overloads to avoid allocations when running on .NET Framework"); + + string? s = value is IFormattable f + ? f.ToString(null, CultureInfo.InvariantCulture) + : value?.ToString(); + +#if NETSTANDARD2_0 + return AppendFormatted(s); +#else + return AppendFormatted(s.AsSpan()); +#endif + } + +#if NETSTANDARD2_0 + public bool AppendFormatted(string? value) +#else + public bool AppendFormatted(scoped ReadOnlySpan value) +#endif + { + if (Utf8Helper.TryGetBytes(value, _buffer.GetSpan(), out int bytesWritten)) + { + _buffer.Advance(bytesWritten); + return true; + } + + return Fail(); + } + + public bool AppendFormatted(scoped ReadOnlySpan utf8Value) + { + if (utf8Value.TryCopyTo(_buffer.GetSpan())) + { + _buffer.Advance(utf8Value.Length); + return true; + } + + return Fail(); + } + + private bool Fail() + { + _success = false; + return false; + } + } } From 4d846622885dcbacfb3f31ea7ef12a44750b7fd3 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Mon, 25 Dec 2023 17:08:40 +0100 Subject: [PATCH 02/30] Use SpreadsheetBuffer.TryWrite for number DataCells --- .../Number/DoubleCellValueWriter.cs | 6 +++++ .../Number/FloatCellValueWriter.cs | 6 +++++ .../Number/IntegerCellValueWriter.cs | 6 +++++ .../Number/NumberCellValueWriter.cs | 5 ----- .../Number/NumberCellValueWriterBase.cs | 4 ++-- SpreadCheetah/SpreadsheetBuffer.cs | 22 +++++++++++++++++++ 6 files changed, 42 insertions(+), 7 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs index c587afa6..607a1b9a 100644 --- a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs @@ -1,3 +1,4 @@ +using SpreadCheetah.Styling.Internal; using System.Buffers.Text; namespace SpreadCheetah.CellValueWriters.Number; @@ -8,4 +9,9 @@ protected override bool TryWriteValue(in DataCell cell, Span destination, { return Utf8Formatter.TryFormat(cell.NumberValue.DoubleValue, destination, out bytesWritten); } + + public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) + { + return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.DoubleValue}{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs index 721de7e6..e515dd1d 100644 --- a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs @@ -1,3 +1,4 @@ +using SpreadCheetah.Styling.Internal; using System.Buffers.Text; namespace SpreadCheetah.CellValueWriters.Number; @@ -8,4 +9,9 @@ protected override bool TryWriteValue(in DataCell cell, Span destination, { return Utf8Formatter.TryFormat(cell.NumberValue.FloatValue, destination, out bytesWritten); } + + public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) + { + return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.FloatValue}{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs index 097161ac..314d6a45 100644 --- a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs @@ -1,3 +1,4 @@ +using SpreadCheetah.Styling.Internal; using System.Buffers.Text; namespace SpreadCheetah.CellValueWriters.Number; @@ -8,4 +9,9 @@ protected override bool TryWriteValue(in DataCell cell, Span destination, { return Utf8Formatter.TryFormat(cell.NumberValue.IntValue, destination, out bytesWritten); } + + public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) + { + return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.IntValue}{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs index ec4eb6cc..4e17a3f4 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs @@ -8,11 +8,6 @@ internal abstract class NumberCellValueWriter : NumberCellValueWriterBase { protected override int GetStyleId(StyleId styleId) => styleId.Id; - public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) - { - return TryWriteCell(cell, buffer); - } - public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { return TryWriteCell(formulaText, cachedValue, styleId?.Id, buffer); diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index 01659e39..18248406 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -9,9 +9,9 @@ internal abstract class NumberCellValueWriterBase : CellValueWriter protected abstract int GetStyleId(StyleId styleId); protected abstract bool TryWriteValue(in DataCell cell, Span destination, out int bytesWritten); - private static ReadOnlySpan BeginDataCell => ""u8; + protected static ReadOnlySpan BeginDataCell => ""u8; private static ReadOnlySpan EndStyleBeginValue => "\">"u8; - private static ReadOnlySpan EndDefaultCell => ""u8; + protected static ReadOnlySpan EndDefaultCell => ""u8; protected bool TryWriteCell(in DataCell cell, SpreadsheetBuffer buffer) { diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index 9d93fa5c..0213e30b 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -92,6 +92,28 @@ public bool AppendFormatted(int value) return Fail(); } + public bool AppendFormatted(float value) + { + if (Utf8Formatter.TryFormat(value, _buffer.GetSpan(), out var bytesWritten)) + { + _buffer.Advance(bytesWritten); + return true; + } + + return Fail(); + } + + public bool AppendFormatted(double value) + { + if (Utf8Formatter.TryFormat(value, _buffer.GetSpan(), out var bytesWritten)) + { + _buffer.Advance(bytesWritten); + return true; + } + + return Fail(); + } + public bool AppendFormatted(T value) { Debug.Fail("Create non-generic overloads to avoid allocations when running on .NET Framework"); From 3e56f8e7fb457b580c498dd6a11114c955a74d7a Mon Sep 17 00:00:00 2001 From: sveinungf Date: Mon, 25 Dec 2023 18:48:41 +0100 Subject: [PATCH 03/30] Write styled number cells with SpreadsheetBuffer.TryWrite --- .../Number/DoubleCellValueWriter.cs | 10 +++++ .../Number/FloatCellValueWriter.cs | 10 +++++ .../Number/IntegerCellValueWriter.cs | 10 +++++ .../Number/NumberCellValueWriterBase.cs | 40 +------------------ .../Time/DateTimeCellValueWriter.cs | 21 ++++++++-- 5 files changed, 48 insertions(+), 43 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs index 607a1b9a..e5eec9f3 100644 --- a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs @@ -1,3 +1,5 @@ +using SpreadCheetah.Helpers; +using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; using System.Buffers.Text; @@ -14,4 +16,12 @@ public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyli { return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.DoubleValue}{EndDefaultCell}"); } + + public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) + { + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndStyleBeginValue}" + + $"{cell.NumberValue.DoubleValue}" + + $"{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs index e515dd1d..353e6dae 100644 --- a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs @@ -1,3 +1,5 @@ +using SpreadCheetah.Helpers; +using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; using System.Buffers.Text; @@ -14,4 +16,12 @@ public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyli { return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.FloatValue}{EndDefaultCell}"); } + + public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) + { + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndStyleBeginValue}" + + $"{cell.NumberValue.FloatValue}" + + $"{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs index 314d6a45..038c5eed 100644 --- a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs @@ -1,3 +1,5 @@ +using SpreadCheetah.Helpers; +using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; using System.Buffers.Text; @@ -14,4 +16,12 @@ public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyli { return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.IntValue}{EndDefaultCell}"); } + + public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) + { + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndStyleBeginValue}" + + $"{cell.NumberValue.IntValue}" + + $"{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index 18248406..82b2e7d2 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -10,42 +10,9 @@ internal abstract class NumberCellValueWriterBase : CellValueWriter protected abstract bool TryWriteValue(in DataCell cell, Span destination, out int bytesWritten); protected static ReadOnlySpan BeginDataCell => ""u8; - private static ReadOnlySpan EndStyleBeginValue => "\">"u8; + protected static ReadOnlySpan EndStyleBeginValue => "\">"u8; protected static ReadOnlySpan EndDefaultCell => ""u8; - protected bool TryWriteCell(in DataCell cell, SpreadsheetBuffer buffer) - { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!BeginDataCell.TryCopyTo(bytes, ref written)) return false; - if (!TryWriteValue(cell, bytes.Slice(written), out var valueLength)) return false; - written += valueLength; - - if (!EndDefaultCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - - protected bool TryWriteCell(in DataCell cell, int styleId, SpreadsheetBuffer buffer) - { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!StyledCellHelper.BeginStyledNumberCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId, bytes, ref written)) return false; - if (!EndStyleBeginValue.TryCopyTo(bytes, ref written)) return false; - - if (!TryWriteValue(cell, bytes.Slice(written), out var valueLength)) return false; - written += valueLength; - - if (!EndDefaultCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - protected bool TryWriteCell(string formulaText, in DataCell cachedValue, int? styleId, SpreadsheetBuffer buffer) { var bytes = buffer.GetSpan(); @@ -62,11 +29,6 @@ protected bool TryWriteCell(string formulaText, in DataCell cachedValue, int? st return true; } - public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) - { - return TryWriteCell(cell, GetStyleId(styleId), buffer); - } - public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) { return TryWriteCellWithReference(cell, GetStyleId(styleId), state); diff --git a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs index 1df01cd8..9480647a 100644 --- a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs @@ -1,5 +1,6 @@ using SpreadCheetah.CellValueWriters.Number; using SpreadCheetah.CellWriters; +using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; using System.Buffers.Text; @@ -17,10 +18,14 @@ protected override bool TryWriteValue(in DataCell cell, Span destination, public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { - var defaultStyleId = defaultStyling?.DateTimeStyleId; - return defaultStyleId is not null - ? TryWriteCell(cell, defaultStyleId.Value, buffer) - : TryWriteCell(cell, buffer); + return defaultStyling?.DateTimeStyleId is { } styleId + ? TryWriteDateTimeCell(cell, styleId, buffer) + : buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.DoubleValue}{EndDefaultCell}"); + } + + public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) + { + return TryWriteDateTimeCell(cell, styleId.DateTimeId, buffer); } public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) @@ -29,6 +34,14 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S return TryWriteCell(formulaText, cachedValue, actualStyleId, buffer); } + private static bool TryWriteDateTimeCell(in DataCell cell, int styleId, SpreadsheetBuffer buffer) + { + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{styleId}{EndStyleBeginValue}" + + $"{cell.NumberValue.DoubleValue}" + + $"{EndDefaultCell}"); + } + public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { var defaultStyleId = defaultStyling?.DateTimeStyleId; From e998aac859d19314cf223fc4db30fe9fe434dc75 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 00:42:18 +0100 Subject: [PATCH 04/30] Write integer DataCell with reference using SpreadsheetBuffer.TryWrite --- .../Number/IntegerCellValueWriter.cs | 9 +++++++++ .../Number/NumberCellValueWriterBase.cs | 2 +- SpreadCheetah/SpreadsheetBuffer.cs | 13 +++++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) diff --git a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs index 038c5eed..66ca5e58 100644 --- a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs @@ -1,3 +1,4 @@ +using SpreadCheetah.CellWriters; using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; @@ -24,4 +25,12 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet $"{cell.NumberValue.IntValue}" + $"{EndDefaultCell}"); } + + public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) + { + return state.Buffer.TryWrite( + $"{state}{EndStyleBeginValue}" + + $"{cell.NumberValue.IntValue}" + + $"{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index 82b2e7d2..dd54e839 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -10,7 +10,7 @@ internal abstract class NumberCellValueWriterBase : CellValueWriter protected abstract bool TryWriteValue(in DataCell cell, Span destination, out int bytesWritten); protected static ReadOnlySpan BeginDataCell => ""u8; - protected static ReadOnlySpan EndStyleBeginValue => "\">"u8; + protected static ReadOnlySpan EndStyleBeginValue => "\">"u8; // TODO: Rename protected static ReadOnlySpan EndDefaultCell => ""u8; protected bool TryWriteCell(string formulaText, in DataCell cachedValue, int? styleId, SpreadsheetBuffer buffer) diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index 0213e30b..ee31aa8f 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -1,3 +1,4 @@ +using SpreadCheetah.CellWriters; using SpreadCheetah.Helpers; using System.Buffers.Text; using System.Diagnostics; @@ -155,6 +156,18 @@ public bool AppendFormatted(scoped ReadOnlySpan utf8Value) return Fail(); } + public bool AppendFormatted(CellWriterState state) + { + var bytes = _buffer.GetSpan(); + var written = 0; + + if (!" Date: Tue, 26 Dec 2023 01:02:06 +0100 Subject: [PATCH 05/30] Fix premature advancement of the buffer in the SpreadsheetBuffer string interpolation handler --- SpreadCheetah/SpreadsheetBuffer.cs | 43 +++++++++++++++++------------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index ee31aa8f..cb2673b8 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -46,13 +46,20 @@ public ValueTask FlushToStreamAsync(Stream stream, CancellationToken token) public bool TryWrite([InterpolatedStringHandlerArgument("")] ref TryWriteInterpolatedStringHandler handler) { - return handler._success; + if (handler._success) + { + Advance(handler._pos); + return true; + } + + return false; } [InterpolatedStringHandler] public ref struct TryWriteInterpolatedStringHandler { private readonly SpreadsheetBuffer _buffer; + internal int _pos; internal bool _success; public TryWriteInterpolatedStringHandler(int literalLength, int formattedCount, SpreadsheetBuffer buffer, out bool shouldAppend) @@ -67,14 +74,14 @@ public bool AppendLiteral(string value) { if (value is not null) { - var dest = _buffer.GetSpan(); + var dest = _buffer.GetSpan().Slice(_pos); #if NET8_0_OR_GREATER if (System.Text.Unicode.Utf8.TryWrite(dest, CultureInfo.InvariantCulture, $"{value}", out var bytesWritten)) #else if (Utf8Helper.TryGetBytes(value, dest, out var bytesWritten)) #endif { - _buffer.Advance(bytesWritten); + _pos += bytesWritten; return true; } } @@ -84,9 +91,9 @@ public bool AppendLiteral(string value) public bool AppendFormatted(int value) { - if (Utf8Formatter.TryFormat(value, _buffer.GetSpan(), out var bytesWritten)) + if (Utf8Formatter.TryFormat(value, _buffer.GetSpan().Slice(_pos), out var bytesWritten)) { - _buffer.Advance(bytesWritten); + _pos += bytesWritten; return true; } @@ -95,9 +102,9 @@ public bool AppendFormatted(int value) public bool AppendFormatted(float value) { - if (Utf8Formatter.TryFormat(value, _buffer.GetSpan(), out var bytesWritten)) + if (Utf8Formatter.TryFormat(value, _buffer.GetSpan().Slice(_pos), out var bytesWritten)) { - _buffer.Advance(bytesWritten); + _pos += bytesWritten; return true; } @@ -106,9 +113,9 @@ public bool AppendFormatted(float value) public bool AppendFormatted(double value) { - if (Utf8Formatter.TryFormat(value, _buffer.GetSpan(), out var bytesWritten)) + if (Utf8Formatter.TryFormat(value, _buffer.GetSpan().Slice(_pos), out var bytesWritten)) { - _buffer.Advance(bytesWritten); + _pos += bytesWritten; return true; } @@ -136,9 +143,9 @@ public bool AppendFormatted(string? value) public bool AppendFormatted(scoped ReadOnlySpan value) #endif { - if (Utf8Helper.TryGetBytes(value, _buffer.GetSpan(), out int bytesWritten)) + if (Utf8Helper.TryGetBytes(value, _buffer.GetSpan().Slice(_pos), out int bytesWritten)) { - _buffer.Advance(bytesWritten); + _pos += bytesWritten; return true; } @@ -147,9 +154,9 @@ public bool AppendFormatted(scoped ReadOnlySpan value) public bool AppendFormatted(scoped ReadOnlySpan utf8Value) { - if (utf8Value.TryCopyTo(_buffer.GetSpan())) + if (utf8Value.TryCopyTo(_buffer.GetSpan().Slice(_pos))) { - _buffer.Advance(utf8Value.Length); + _pos += utf8Value.Length; return true; } @@ -158,13 +165,13 @@ public bool AppendFormatted(scoped ReadOnlySpan utf8Value) public bool AppendFormatted(CellWriterState state) { - var bytes = _buffer.GetSpan(); - var written = 0; + var bytes = _buffer.GetSpan().Slice(_pos); + var bytesWritten = 0; - if (!" Date: Tue, 26 Dec 2023 01:02:58 +0100 Subject: [PATCH 06/30] TryWriteCellWithReference for number cells using SpreadsheetBuffer.TryWrite --- .../Number/DoubleCellValueWriter.cs | 17 +++++++++++++++++ .../Number/FloatCellValueWriter.cs | 17 +++++++++++++++++ .../Number/IntegerCellValueWriter.cs | 8 ++++++++ .../Number/NumberCellValueWriter.cs | 5 ----- 4 files changed, 42 insertions(+), 5 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs index e5eec9f3..901df451 100644 --- a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs @@ -1,3 +1,4 @@ +using SpreadCheetah.CellWriters; using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; @@ -24,4 +25,20 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet $"{cell.NumberValue.DoubleValue}" + $"{EndDefaultCell}"); } + + public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) + { + return state.Buffer.TryWrite( + $"{state}{EndStyleBeginValue}" + + $"{cell.NumberValue.DoubleValue}" + + $"{EndDefaultCell}"); + } + + public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) + { + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndStyleBeginValue}" + + $"{cell.NumberValue.DoubleValue}" + + $"{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs index 353e6dae..22508c85 100644 --- a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs @@ -1,3 +1,4 @@ +using SpreadCheetah.CellWriters; using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; @@ -24,4 +25,20 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet $"{cell.NumberValue.FloatValue}" + $"{EndDefaultCell}"); } + + public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) + { + return state.Buffer.TryWrite( + $"{state}{EndStyleBeginValue}" + + $"{cell.NumberValue.FloatValue}" + + $"{EndDefaultCell}"); + } + + public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) + { + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndStyleBeginValue}" + + $"{cell.NumberValue.FloatValue}" + + $"{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs index 66ca5e58..0033db0f 100644 --- a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs @@ -33,4 +33,12 @@ public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? $"{cell.NumberValue.IntValue}" + $"{EndDefaultCell}"); } + + public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) + { + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndStyleBeginValue}" + + $"{cell.NumberValue.IntValue}" + + $"{EndDefaultCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs index 4e17a3f4..b1480f40 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs @@ -13,11 +13,6 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S return TryWriteCell(formulaText, cachedValue, styleId?.Id, buffer); } - public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) - { - return TryWriteCellWithReference(cell, state); - } - public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { return TryWriteCellWithReference(formulaText, cachedValue, styleId?.Id, state); From 429068249598c53352ce3f88250360fbee7ae708 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 01:28:38 +0100 Subject: [PATCH 07/30] Write DateTime cells with reference using SpreadsheetBuffer.TryWrite --- .../Number/NumberCellValueWriterBase.cs | 42 ------------------- .../Time/DateTimeCellValueWriter.cs | 24 +++++++++-- 2 files changed, 20 insertions(+), 46 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index dd54e839..155effd6 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -29,48 +29,6 @@ protected bool TryWriteCell(string formulaText, in DataCell cachedValue, int? st return true; } - public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) - { - return TryWriteCellWithReference(cell, GetStyleId(styleId), state); - } - - protected bool TryWriteCellWithReference(in DataCell cell, CellWriterState state) - { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\">"u8.TryCopyTo(bytes, ref written)) return false; - if (!TryWriteValue(cell, bytes.Slice(written), out var valueLength)) return false; - written += valueLength; - - if (!EndDefaultCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - - protected bool TryWriteCellWithReference(in DataCell cell, int styleId, CellWriterState state) - { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!StyledCellHelper.EndReferenceBeginStyleId.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId, bytes, ref written)) return false; - if (!EndStyleBeginValue.TryCopyTo(bytes, ref written)) return false; - - if (!TryWriteValue(cell, bytes.Slice(written), out var valueLength)) return false; - written += valueLength; - - if (!EndDefaultCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - protected bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, int? styleId, CellWriterState state) { var buffer = state.Buffer; diff --git a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs index 9480647a..8c37ff55 100644 --- a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs @@ -44,10 +44,18 @@ private static bool TryWriteDateTimeCell(in DataCell cell, int styleId, Spreadsh public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { - var defaultStyleId = defaultStyling?.DateTimeStyleId; - return defaultStyleId is not null - ? TryWriteCellWithReference(cell, defaultStyleId.Value, state) - : TryWriteCellWithReference(cell, state); + if (defaultStyling?.DateTimeStyleId is { } styleId) + return TryWriteDateTimeCellWithReference(cell, styleId, state); + + return state.Buffer.TryWrite( + $"{state}{EndStyleBeginValue}" + + $"{cell.NumberValue.DoubleValue}" + + $"{EndDefaultCell}"); + } + + public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) + { + return TryWriteDateTimeCellWithReference(cell, styleId.DateTimeId, state); } public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) @@ -56,6 +64,14 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c return TryWriteCellWithReference(formulaText, cachedValue, actualStyleId, state); } + private static bool TryWriteDateTimeCellWithReference(in DataCell cell, int styleId, CellWriterState state) + { + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId}{EndStyleBeginValue}" + + $"{cell.NumberValue.DoubleValue}" + + $"{EndDefaultCell}"); + } + public override bool WriteFormulaStartElement(StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { var actualStyleId = styleId?.DateTimeId ?? defaultStyling?.DateTimeStyleId; From aa2e99236c870f3d662497629430549bcac99d22 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 15:20:38 +0100 Subject: [PATCH 08/30] Use SpreadsheetBuffer.TryWrite for string data cells --- .../CellValueWriters/StringCellValueWriter.cs | 10 +--------- SpreadCheetah/SpreadsheetBuffer.cs | 9 +-------- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs b/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs index 8f1f3e59..2e91d651 100644 --- a/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs @@ -16,15 +16,7 @@ internal sealed class StringCellValueWriter : CellValueWriter public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!BeginStringCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(cell.StringValue, bytes, ref written)) return false; - if (!EndStringCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return buffer.TryWrite($"{BeginStringCell}{cell.StringValue}{EndStringCell}"); } public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index cb2673b8..46ca6bab 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -69,6 +69,7 @@ public TryWriteInterpolatedStringHandler(int literalLength, int formattedCount, _success = shouldAppend = buffer.FreeCapacity >= literalLength; } + // TODO: Remove or throw? Literals should rather use ReadOnlySpan [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool AppendLiteral(string value) { @@ -130,18 +131,10 @@ public bool AppendFormatted(T value) ? f.ToString(null, CultureInfo.InvariantCulture) : value?.ToString(); -#if NETSTANDARD2_0 return AppendFormatted(s); -#else - return AppendFormatted(s.AsSpan()); -#endif } -#if NETSTANDARD2_0 public bool AppendFormatted(string? value) -#else - public bool AppendFormatted(scoped ReadOnlySpan value) -#endif { if (Utf8Helper.TryGetBytes(value, _buffer.GetSpan().Slice(_pos), out int bytesWritten)) { From d6b8e4037925ba3631bb85cbc6cd555543d2ca34 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 15:42:01 +0100 Subject: [PATCH 09/30] Remove literal length check in string interpolation handler --- SpreadCheetah/SpreadsheetBuffer.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index 46ca6bab..9750e658 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -62,11 +62,12 @@ public ref struct TryWriteInterpolatedStringHandler internal int _pos; internal bool _success; - public TryWriteInterpolatedStringHandler(int literalLength, int formattedCount, SpreadsheetBuffer buffer, out bool shouldAppend) + public TryWriteInterpolatedStringHandler(int literalLength, int formattedCount, SpreadsheetBuffer buffer) { + _ = literalLength; _ = formattedCount; _buffer = buffer; - _success = shouldAppend = buffer.FreeCapacity >= literalLength; + _success = true; } // TODO: Remove or throw? Literals should rather use ReadOnlySpan From 4fd7dfbee98309c014fcef71247eecbd70c2ff2e Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 15:53:23 +0100 Subject: [PATCH 10/30] Write number formula cells with SpreadsheetBuffer.TryWrite --- .../Number/DoubleCellValueWriter.cs | 20 +++++++++++++++++++ .../Number/FloatCellValueWriter.cs | 20 +++++++++++++++++++ .../Number/IntegerCellValueWriter.cs | 20 +++++++++++++++++++ .../Number/NumberCellValueWriter.cs | 5 ----- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs index 901df451..5d499a70 100644 --- a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs @@ -26,6 +26,26 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet $"{EndDefaultCell}"); } + public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) + { + if (styleId is { } style) + { + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.DoubleValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + + return buffer.TryWrite( + $"{FormulaCellHelper.BeginNumberFormulaCell}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.DoubleValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { return state.Buffer.TryWrite( diff --git a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs index 22508c85..69b2310a 100644 --- a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs @@ -26,6 +26,26 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet $"{EndDefaultCell}"); } + public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) + { + if (styleId is { } style) + { + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.FloatValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + + return buffer.TryWrite( + $"{FormulaCellHelper.BeginNumberFormulaCell}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.FloatValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { return state.Buffer.TryWrite( diff --git a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs index 0033db0f..10643332 100644 --- a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs @@ -26,6 +26,26 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet $"{EndDefaultCell}"); } + public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) + { + if (styleId is { } style) + { + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.IntValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + + return buffer.TryWrite( + $"{FormulaCellHelper.BeginNumberFormulaCell}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.IntValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { return state.Buffer.TryWrite( diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs index b1480f40..e1a5d55e 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs @@ -8,11 +8,6 @@ internal abstract class NumberCellValueWriter : NumberCellValueWriterBase { protected override int GetStyleId(StyleId styleId) => styleId.Id; - public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) - { - return TryWriteCell(formulaText, cachedValue, styleId?.Id, buffer); - } - public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { return TryWriteCellWithReference(formulaText, cachedValue, styleId?.Id, state); From 23471839ce53e2acafced67394de23f32801765f Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 15:57:28 +0100 Subject: [PATCH 11/30] Write DateTime formula cells with SpreadsheetBuffer.TryWrite --- .../Number/NumberCellValueWriterBase.cs | 16 ---------------- .../Time/DateTimeCellValueWriter.cs | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 17 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index 155effd6..6f01f0c7 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -13,22 +13,6 @@ internal abstract class NumberCellValueWriterBase : CellValueWriter protected static ReadOnlySpan EndStyleBeginValue => "\">"u8; // TODO: Rename protected static ReadOnlySpan EndDefaultCell => ""u8; - protected bool TryWriteCell(string formulaText, in DataCell cachedValue, int? styleId, SpreadsheetBuffer buffer) - { - var bytes = buffer.GetSpan(); - - if (!TryWriteFormulaCellStart(styleId, bytes, out var written)) return false; - if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; - if (!FormulaCellHelper.EndFormulaBeginCachedValue.TryCopyTo(bytes, ref written)) return false; - if (!TryWriteValue(cachedValue, bytes.Slice(written), out var valueLength)) return false; - written += valueLength; - - if (!FormulaCellHelper.EndCachedValueEndCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - protected bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, int? styleId, CellWriterState state) { var buffer = state.Buffer; diff --git a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs index 8c37ff55..d1de960b 100644 --- a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs @@ -31,7 +31,22 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { var actualStyleId = styleId?.DateTimeId ?? defaultStyling?.DateTimeStyleId; - return TryWriteCell(formulaText, cachedValue, actualStyleId, buffer); + if (actualStyleId is { } style) + { + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.DoubleValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + + return buffer.TryWrite( + $"{FormulaCellHelper.BeginNumberFormulaCell}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.DoubleValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); } private static bool TryWriteDateTimeCell(in DataCell cell, int styleId, SpreadsheetBuffer buffer) From 06a481c4d7826c7cb37ace466f74ef9d7b53d214 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 16:08:01 +0100 Subject: [PATCH 12/30] Write formula number cells with reference using SpreadsheetBuffer.TryWrite --- .../Number/DoubleCellValueWriter.cs | 20 +++++++++++++++++++ .../Number/FloatCellValueWriter.cs | 20 +++++++++++++++++++ .../Number/IntegerCellValueWriter.cs | 20 +++++++++++++++++++ .../Number/NumberCellValueWriter.cs | 5 ----- SpreadCheetah/Helpers/FormulaCellHelper.cs | 2 +- 5 files changed, 61 insertions(+), 6 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs index 5d499a70..22337279 100644 --- a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs @@ -61,4 +61,24 @@ public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId $"{cell.NumberValue.DoubleValue}" + $"{EndDefaultCell}"); } + + public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) + { + if (styleId is { } style) + { + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.DoubleValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + + return state.Buffer.TryWrite( + $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.DoubleValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs index 69b2310a..db9cba0b 100644 --- a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs @@ -61,4 +61,24 @@ public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId $"{cell.NumberValue.FloatValue}" + $"{EndDefaultCell}"); } + + public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) + { + if (styleId is { } style) + { + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.FloatValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + + return state.Buffer.TryWrite( + $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.FloatValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs index 10643332..f400756a 100644 --- a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs @@ -61,4 +61,24 @@ public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId $"{cell.NumberValue.IntValue}" + $"{EndDefaultCell}"); } + + public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) + { + if (styleId is { } style) + { + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.IntValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + + return state.Buffer.TryWrite( + $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.IntValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs index e1a5d55e..f55552b1 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriter.cs @@ -8,11 +8,6 @@ internal abstract class NumberCellValueWriter : NumberCellValueWriterBase { protected override int GetStyleId(StyleId styleId) => styleId.Id; - public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) - { - return TryWriteCellWithReference(formulaText, cachedValue, styleId?.Id, state); - } - public override bool WriteFormulaStartElement(StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { return WriteFormulaStartElement(styleId?.Id, buffer); diff --git a/SpreadCheetah/Helpers/FormulaCellHelper.cs b/SpreadCheetah/Helpers/FormulaCellHelper.cs index 30f9a7ff..295559a8 100644 --- a/SpreadCheetah/Helpers/FormulaCellHelper.cs +++ b/SpreadCheetah/Helpers/FormulaCellHelper.cs @@ -2,7 +2,7 @@ namespace SpreadCheetah.Helpers; internal static class FormulaCellHelper { - public static ReadOnlySpan EndStyleBeginFormula => "\">"u8; + public static ReadOnlySpan EndStyleBeginFormula => "\">"u8; // TODO: Rename public static ReadOnlySpan BeginNumberFormulaCell => ""u8; public static ReadOnlySpan EndFormulaBeginCachedValue => ""u8; public static ReadOnlySpan EndCachedValueEndCell => ""u8; From 99a627973523db713be5d5707141d37b467b2963 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 16:11:14 +0100 Subject: [PATCH 13/30] Write DateTime formula cells with reference using SpreadsheetBuffer.TryWrite --- .../Number/NumberCellValueWriterBase.cs | 17 ----------------- .../Time/DateTimeCellValueWriter.cs | 17 ++++++++++++++++- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index 6f01f0c7..c6960e17 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -13,23 +13,6 @@ internal abstract class NumberCellValueWriterBase : CellValueWriter protected static ReadOnlySpan EndStyleBeginValue => "\">"u8; // TODO: Rename protected static ReadOnlySpan EndDefaultCell => ""u8; - protected bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, int? styleId, CellWriterState state) - { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - - if (!TryWriteFormulaCellStartWithReference(styleId, state, bytes, out var written)) return false; - if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; - if (!FormulaCellHelper.EndFormulaBeginCachedValue.TryCopyTo(bytes, ref written)) return false; - if (!TryWriteValue(cachedValue, bytes.Slice(written), out var valueLength)) return false; - written += valueLength; - - if (!FormulaCellHelper.EndCachedValueEndCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - public static bool TryWriteFormulaCellStart(int? styleId, Span bytes, out int bytesWritten) { bytesWritten = 0; diff --git a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs index d1de960b..1cda7c36 100644 --- a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs @@ -76,7 +76,22 @@ public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { var actualStyleId = styleId?.DateTimeId ?? defaultStyling?.DateTimeStyleId; - return TryWriteCellWithReference(formulaText, cachedValue, actualStyleId, state); + if (actualStyleId is { } style) + { + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.DoubleValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); + } + + return state.Buffer.TryWrite( + $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.NumberValue.DoubleValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); } private static bool TryWriteDateTimeCellWithReference(in DataCell cell, int styleId, CellWriterState state) From 670d35a0f0dcc7dc48504eef4f0c4473a853fa9a Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 16:18:19 +0100 Subject: [PATCH 14/30] WriteValuePieceByPiece for number cell writers with SpreadsheetBuffer.TryWrite --- .../CellValueWriters/Number/DoubleCellValueWriter.cs | 11 +++++------ .../CellValueWriters/Number/FloatCellValueWriter.cs | 11 +++++------ .../CellValueWriters/Number/IntegerCellValueWriter.cs | 11 +++++------ .../Number/NumberCellValueWriterBase.cs | 11 ----------- .../CellValueWriters/Time/DateTimeCellValueWriter.cs | 11 +++++------ 5 files changed, 20 insertions(+), 35 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs index 22337279..e7cf6017 100644 --- a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs @@ -2,17 +2,11 @@ using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; -using System.Buffers.Text; namespace SpreadCheetah.CellValueWriters.Number; internal sealed class DoubleCellValueWriter : NumberCellValueWriter { - protected override bool TryWriteValue(in DataCell cell, Span destination, out int bytesWritten) - { - return Utf8Formatter.TryFormat(cell.NumberValue.DoubleValue, destination, out bytesWritten); - } - public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.DoubleValue}{EndDefaultCell}"); @@ -81,4 +75,9 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c $"{cachedValue.NumberValue.DoubleValue}" + $"{FormulaCellHelper.EndCachedValueEndCell}"); } + + public override bool WriteValuePieceByPiece(in DataCell cell, SpreadsheetBuffer buffer, ref int valueIndex) + { + return buffer.TryWrite($"{cell.NumberValue.DoubleValue}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs index db9cba0b..b3731072 100644 --- a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs @@ -2,17 +2,11 @@ using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; -using System.Buffers.Text; namespace SpreadCheetah.CellValueWriters.Number; internal sealed class FloatCellValueWriter : NumberCellValueWriter { - protected override bool TryWriteValue(in DataCell cell, Span destination, out int bytesWritten) - { - return Utf8Formatter.TryFormat(cell.NumberValue.FloatValue, destination, out bytesWritten); - } - public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.FloatValue}{EndDefaultCell}"); @@ -81,4 +75,9 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c $"{cachedValue.NumberValue.FloatValue}" + $"{FormulaCellHelper.EndCachedValueEndCell}"); } + + public override bool WriteValuePieceByPiece(in DataCell cell, SpreadsheetBuffer buffer, ref int valueIndex) + { + return buffer.TryWrite($"{cell.NumberValue.FloatValue}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs index f400756a..b55d3e45 100644 --- a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs @@ -2,17 +2,11 @@ using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; -using System.Buffers.Text; namespace SpreadCheetah.CellValueWriters.Number; internal sealed class IntegerCellValueWriter : NumberCellValueWriter { - protected override bool TryWriteValue(in DataCell cell, Span destination, out int bytesWritten) - { - return Utf8Formatter.TryFormat(cell.NumberValue.IntValue, destination, out bytesWritten); - } - public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { return buffer.TryWrite($"{BeginDataCell}{cell.NumberValue.IntValue}{EndDefaultCell}"); @@ -81,4 +75,9 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c $"{cachedValue.NumberValue.IntValue}" + $"{FormulaCellHelper.EndCachedValueEndCell}"); } + + public override bool WriteValuePieceByPiece(in DataCell cell, SpreadsheetBuffer buffer, ref int valueIndex) + { + return buffer.TryWrite($"{cell.NumberValue.IntValue}"); + } } diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index c6960e17..0ade0153 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -7,7 +7,6 @@ namespace SpreadCheetah.CellValueWriters.Number; internal abstract class NumberCellValueWriterBase : CellValueWriter { protected abstract int GetStyleId(StyleId styleId); - protected abstract bool TryWriteValue(in DataCell cell, Span destination, out int bytesWritten); protected static ReadOnlySpan BeginDataCell => ""u8; protected static ReadOnlySpan EndStyleBeginValue => "\">"u8; // TODO: Rename @@ -152,16 +151,6 @@ protected static bool WriteFormulaStartElementWithReference(int? styleId, CellWr public override bool CanWriteValuePieceByPiece(in DataCell cell) => true; - public override bool WriteValuePieceByPiece(in DataCell cell, SpreadsheetBuffer buffer, ref int valueIndex) - { - var bytes = buffer.GetSpan(); - if (!TryWriteValue(cell, bytes, out var bytesWritten)) - return false; - - buffer.Advance(bytesWritten); - return true; - } - public override bool TryWriteEndElement(SpreadsheetBuffer buffer) { var bytes = buffer.GetSpan(); diff --git a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs index 1cda7c36..bfdb370d 100644 --- a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs @@ -3,7 +3,6 @@ using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; -using System.Buffers.Text; namespace SpreadCheetah.CellValueWriters.Time; @@ -11,11 +10,6 @@ internal sealed class DateTimeCellValueWriter : NumberCellValueWriterBase { protected override int GetStyleId(StyleId styleId) => styleId.DateTimeId; - protected override bool TryWriteValue(in DataCell cell, Span destination, out int bytesWritten) - { - return Utf8Formatter.TryFormat(cell.NumberValue.DoubleValue, destination, out bytesWritten); - } - public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { return defaultStyling?.DateTimeStyleId is { } styleId @@ -113,4 +107,9 @@ public override bool WriteFormulaStartElementWithReference(StyleId? styleId, Def var actualStyleId = styleId?.DateTimeId ?? defaultStyling?.DateTimeStyleId; return WriteFormulaStartElementWithReference(actualStyleId, state); } + + public override bool WriteValuePieceByPiece(in DataCell cell, SpreadsheetBuffer buffer, ref int valueIndex) + { + return buffer.TryWrite($"{cell.NumberValue.DoubleValue}"); + } } From ff07a52dedf2dc1436093f768802e8eae5b5b7cc Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 16:47:20 +0100 Subject: [PATCH 15/30] Use SpreadsheetBuffer.TryWrite in NumberCellValueWriterBase --- .../CellValueWriters/NullValueWriterBase.cs | 45 +++++- .../Number/NumberCellValueWriterBase.cs | 144 ++---------------- 2 files changed, 59 insertions(+), 130 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs b/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs index 74da17af..8172449b 100644 --- a/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs @@ -41,7 +41,7 @@ protected static bool TryWriteCell(string formulaText, int? styleId, Spreadsheet { var bytes = buffer.GetSpan(); - if (!NumberCellValueWriterBase.TryWriteFormulaCellStart(styleId, bytes, out var written)) return false; + if (!TryWriteFormulaCellStart(styleId, bytes, out var written)) return false; if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; if (!EndFormulaEndCell.TryCopyTo(bytes, ref written)) return false; @@ -49,6 +49,24 @@ protected static bool TryWriteCell(string formulaText, int? styleId, Spreadsheet return true; } + private static bool TryWriteFormulaCellStart(int? styleId, Span bytes, out int bytesWritten) + { + bytesWritten = 0; + var written = 0; + + if (styleId is null) + { + return FormulaCellHelper.BeginNumberFormulaCell.TryCopyTo(bytes, ref bytesWritten); + } + + if (!StyledCellHelper.BeginStyledNumberCell.TryCopyTo(bytes, ref written)) return false; + if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; + if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; + + bytesWritten = written; + return true; + } + public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) { return TryWriteCell(GetStyleId(styleId), buffer); @@ -92,7 +110,7 @@ protected static bool TryWriteCellWithReference(string formulaText, int? styleId var buffer = state.Buffer; var bytes = buffer.GetSpan(); - if (!NumberCellValueWriterBase.TryWriteFormulaCellStartWithReference(styleId, state, bytes, out var written)) return false; + if (!TryWriteFormulaCellStartWithReference(styleId, state, bytes, out var written)) return false; if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; if (!EndFormulaEndCell.TryCopyTo(bytes, ref written)) return false; @@ -100,6 +118,29 @@ protected static bool TryWriteCellWithReference(string formulaText, int? styleId return true; } + private static bool TryWriteFormulaCellStartWithReference(int? styleId, CellWriterState state, Span bytes, out int bytesWritten) + { + bytesWritten = 0; + var written = 0; + + if (styleId is null) + { + if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; + if (!"\">"u8.TryCopyTo(bytes, ref written)) return false; + + bytesWritten = written; + return true; + } + + if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; + if (!StyledCellHelper.EndReferenceBeginStyleId.TryCopyTo(bytes, ref written)) return false; + if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; + if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; + + bytesWritten = written; + return true; + } + public override bool TryWriteEndElement(SpreadsheetBuffer buffer) => true; public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index 0ade0153..5437b657 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -12,165 +12,53 @@ internal abstract class NumberCellValueWriterBase : CellValueWriter protected static ReadOnlySpan EndStyleBeginValue => "\">"u8; // TODO: Rename protected static ReadOnlySpan EndDefaultCell => ""u8; - public static bool TryWriteFormulaCellStart(int? styleId, Span bytes, out int bytesWritten) - { - bytesWritten = 0; - var written = 0; - - if (styleId is null) - { - return FormulaCellHelper.BeginNumberFormulaCell.TryCopyTo(bytes, ref bytesWritten); - } - - if (!StyledCellHelper.BeginStyledNumberCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - bytesWritten = written; - return true; - } - - public static bool TryWriteFormulaCellStartWithReference(int? styleId, CellWriterState state, Span bytes, out int bytesWritten) - { - bytesWritten = 0; - var written = 0; - - if (styleId is null) - { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\">"u8.TryCopyTo(bytes, ref written)) return false; - - bytesWritten = written; - return true; - } - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!StyledCellHelper.EndReferenceBeginStyleId.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - bytesWritten = written; - return true; - } - public override bool WriteStartElement(SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!BeginDataCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return buffer.TryWrite($"{BeginDataCell}"); } public override bool WriteStartElement(StyleId styleId, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!StyledCellHelper.BeginStyledNumberCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(GetStyleId(styleId), bytes, ref written)) return false; - if (!EndStyleBeginValue.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + var style = GetStyleId(styleId); + return buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{EndStyleBeginValue}"); } public override bool WriteStartElementWithReference(CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\">"u8.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return state.Buffer.TryWrite($"{state}{EndStyleBeginValue}"); } public override bool WriteStartElementWithReference(StyleId styleId, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!StyledCellHelper.EndReferenceBeginStyleId.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(GetStyleId(styleId), bytes, ref written)) return false; - if (!EndStyleBeginValue.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + var style = GetStyleId(styleId); + return state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{EndStyleBeginValue}"); } protected static bool WriteFormulaStartElement(int? styleId, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!FormulaCellHelper.BeginNumberFormulaCell.TryCopyTo(bytes, ref written)) return false; - buffer.Advance(written); - return true; - } - - if (!StyledCellHelper.BeginStyledNumberCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return styleId is { } style + ? buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndStyleBeginFormula}") + : buffer.TryWrite($"{FormulaCellHelper.BeginNumberFormulaCell}"); } protected static bool WriteFormulaStartElementWithReference(int? styleId, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\">"u8.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!StyledCellHelper.EndReferenceBeginStyleId.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return styleId is { } style + ? state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndStyleBeginFormula}") + : state.Buffer.TryWrite($"{state}{FormulaCellHelper.EndStyleBeginFormula}"); } public override bool CanWriteValuePieceByPiece(in DataCell cell) => true; public override bool TryWriteEndElement(SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - if (!EndDefaultCell.TryCopyTo(bytes)) - return false; - - buffer.Advance(EndDefaultCell.Length); - return true; + return buffer.TryWrite($"{EndDefaultCell}"); } public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) { - if (cell.Formula is null) - return TryWriteEndElement(buffer); - - var bytes = buffer.GetSpan(); - if (!FormulaCellHelper.EndCachedValueEndCell.TryCopyTo(bytes)) - return false; - - buffer.Advance(FormulaCellHelper.EndCachedValueEndCell.Length); - return true; + return cell.Formula is null + ? TryWriteEndElement(buffer) + : buffer.TryWrite($"{FormulaCellHelper.EndCachedValueEndCell}"); } } From a20f99b1c2e145f2e5344a888c3312486e84762f Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 21:23:05 +0100 Subject: [PATCH 16/30] Use SpreadsheetBuffer.TryWrite in NullValueWriterBase --- .../CellValueWriters/NullValueWriterBase.cs | 167 ++++-------------- 1 file changed, 30 insertions(+), 137 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs b/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs index 8172449b..8af459c0 100644 --- a/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs @@ -1,4 +1,3 @@ -using SpreadCheetah.CellValueWriters.Number; using SpreadCheetah.CellWriters; using SpreadCheetah.Helpers; using SpreadCheetah.Styling; @@ -10,61 +9,33 @@ internal abstract class NullValueWriterBase : CellValueWriter protected abstract int GetStyleId(StyleId styleId); private static ReadOnlySpan NullDataCell => ""u8; - private static ReadOnlySpan EndStyleNullValue => "\"/>"u8; + private static ReadOnlySpan EndStyleNullValue => "\"/>"u8; // TODO: Rename private static ReadOnlySpan EndFormulaEndCell => ""u8; protected static bool TryWriteCell(SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!NullDataCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return buffer.TryWrite($"{NullDataCell}"); } protected static bool TryWriteCell(int styleId, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!StyledCellHelper.BeginStyledNumberCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId, bytes, ref written)) return false; - if (!EndStyleNullValue.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{styleId}{EndStyleNullValue}"); } protected static bool TryWriteCell(string formulaText, int? styleId, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - - if (!TryWriteFormulaCellStart(styleId, bytes, out var written)) return false; - if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; - if (!EndFormulaEndCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - - private static bool TryWriteFormulaCellStart(int? styleId, Span bytes, out int bytesWritten) - { - bytesWritten = 0; - var written = 0; - - if (styleId is null) + if (styleId is { } style) { - return FormulaCellHelper.BeginNumberFormulaCell.TryCopyTo(bytes, ref bytesWritten); + return buffer.TryWrite( + $"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaEndCell}"); } - if (!StyledCellHelper.BeginStyledNumberCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - bytesWritten = written; - return true; + return buffer.TryWrite( + $"{FormulaCellHelper.BeginNumberFormulaCell}" + + $"{formulaText}" + + $"{EndFormulaEndCell}"); } public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) @@ -74,15 +45,7 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet protected static bool TryWriteCellWithReference(CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\"/>"u8.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return state.Buffer.TryWrite($"{state}{EndStyleNullValue}"); } public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) @@ -92,114 +55,44 @@ public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId protected static bool TryWriteCellWithReference(int styleId, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!StyledCellHelper.EndReferenceBeginStyleId.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId, bytes, ref written)) return false; - if (!EndStyleNullValue.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId}{EndStyleNullValue}"); } protected static bool TryWriteCellWithReference(string formulaText, int? styleId, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - - if (!TryWriteFormulaCellStartWithReference(styleId, state, bytes, out var written)) return false; - if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; - if (!EndFormulaEndCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - - private static bool TryWriteFormulaCellStartWithReference(int? styleId, CellWriterState state, Span bytes, out int bytesWritten) - { - bytesWritten = 0; - var written = 0; - - if (styleId is null) + if (styleId is { } style) { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\">"u8.TryCopyTo(bytes, ref written)) return false; - - bytesWritten = written; - return true; + return state.Buffer.TryWrite( + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaEndCell}"); } - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!StyledCellHelper.EndReferenceBeginStyleId.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - bytesWritten = written; - return true; + return state.Buffer.TryWrite( + $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaEndCell}"); } public override bool TryWriteEndElement(SpreadsheetBuffer buffer) => true; public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) { - if (cell.Formula is null) - return true; - - var bytes = buffer.GetSpan(); - if (EndFormulaEndCell.TryCopyTo(bytes)) - { - buffer.Advance(EndFormulaEndCell.Length); - return true; - } - - return false; + return cell.Formula is null || buffer.TryWrite($"{EndFormulaEndCell}"); } protected static bool WriteFormulaStartElement(int? styleId, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!FormulaCellHelper.BeginNumberFormulaCell.TryCopyTo(bytes, ref written)) return false; - buffer.Advance(written); - return true; - } - - if (!StyledCellHelper.BeginStyledNumberCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return styleId is { } style + ? buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndStyleBeginFormula}") + : buffer.TryWrite($"{FormulaCellHelper.BeginNumberFormulaCell}"); } protected static bool WriteFormulaStartElementWithReference(int? styleId, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\">"u8.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!StyledCellHelper.EndReferenceBeginStyleId.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Value, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return styleId is { } style + ? state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndStyleBeginFormula}") + : state.Buffer.TryWrite($"{state}{FormulaCellHelper.EndStyleBeginFormula}"); } public override bool WriteStartElement(SpreadsheetBuffer buffer) => TryWriteCell(buffer); From f3bfda169fc9b744b41d0e7c68332d617e0758e4 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 22:00:26 +0100 Subject: [PATCH 17/30] Use SpreadsheetBuffer.TryWrite for boolean cells --- .../Boolean/BooleanCellValueWriter.cs | 148 ++---------------- .../Boolean/FalseBooleanCellValueWriter.cs | 65 ++++---- .../Boolean/TrueBooleanCellValueWriter.cs | 65 ++++---- 3 files changed, 87 insertions(+), 191 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Boolean/BooleanCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Boolean/BooleanCellValueWriter.cs index b0f33783..d2ebee4a 100644 --- a/SpreadCheetah/CellValueWriters/Boolean/BooleanCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Boolean/BooleanCellValueWriter.cs @@ -7,13 +7,15 @@ namespace SpreadCheetah.CellValueWriters.Boolean; internal abstract class BooleanCellValueWriter : CellValueWriter { - private static ReadOnlySpan BeginStyledBooleanCell => " BeginBooleanFormulaCell => ""u8; + protected static ReadOnlySpan BeginStyledBooleanCell => " BeginBooleanFormulaCell => ""u8; + protected static ReadOnlySpan EndReferenceBeginStyled => "\" t=\"b\" s=\""u8; + protected static ReadOnlySpan EndReferenceBeginFormula => "\" t=\"b\">"u8; protected abstract bool TryWriteCell(SpreadsheetBuffer buffer); + protected abstract bool TryWriteCell(StyleId styleId, SpreadsheetBuffer buffer); protected abstract bool TryWriteCellWithReference(CellWriterState state); - protected abstract bool TryWriteEndStyleValue(Span bytes, out int bytesWritten); - protected abstract bool TryWriteEndFormulaValue(Span bytes, out int bytesWritten); + protected abstract bool TryWriteCellWithReference(StyleId styleId, CellWriterState state); public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { @@ -25,43 +27,6 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet return TryWriteCell(styleId, buffer); } - private bool TryWriteCell(StyleId styleId, SpreadsheetBuffer buffer) - { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!BeginStyledBooleanCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!TryWriteEndStyleValue(bytes.Slice(written), out var endLength)) return false; - written += endLength; - - buffer.Advance(written); - return true; - } - - public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) - { - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!BeginBooleanFormulaCell.TryCopyTo(bytes, ref written)) return false; - } - else - { - if (!BeginStyledBooleanCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - } - - if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; - if (!TryWriteEndFormulaValue(bytes.Slice(written), out var endLength)) return false; - - buffer.Advance(written + endLength); - return true; - } - public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { return TryWriteCellWithReference(state); @@ -72,107 +37,20 @@ public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId return TryWriteCellWithReference(styleId, state); } - private bool TryWriteCellWithReference(StyleId styleId, CellWriterState state) - { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"b\" s=\""u8.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!TryWriteEndStyleValue(bytes.Slice(written), out var endLength)) return false; - written += endLength; - - buffer.Advance(written); - return true; - } - - public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) - { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"b\">"u8.TryCopyTo(bytes, ref written)) return false; - } - else - { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"b\" s=\""u8.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - } - - if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; - if (!TryWriteEndFormulaValue(bytes.Slice(written), out var endLength)) return false; - - buffer.Advance(written + endLength); - return true; - } - public override bool TryWriteEndElement(SpreadsheetBuffer buffer) => true; - public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) - { - if (cell.Formula is null) - return true; - - var bytes = buffer.GetSpan(); - if (TryWriteEndFormulaValue(bytes, out var bytesWritten)) - { - buffer.Advance(bytesWritten); - return true; - } - - return false; - } - public override bool WriteFormulaStartElement(StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!BeginBooleanFormulaCell.TryCopyTo(bytes, ref written)) return false; - buffer.Advance(written); - return true; - } - - if (!BeginStyledBooleanCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return styleId is { } style + ? buffer.TryWrite($"{BeginStyledBooleanCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}") + : buffer.TryWrite($"{BeginBooleanFormulaCell}"); } public override bool WriteFormulaStartElementWithReference(StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"b\">"u8.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"b\" s=\""u8.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return styleId is { } style + ? state.Buffer.TryWrite($"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}") + : state.Buffer.TryWrite($"{state}{EndReferenceBeginFormula}"); } public override bool WriteStartElement(SpreadsheetBuffer buffer) => TryWriteCell(buffer); @@ -181,7 +59,7 @@ public override bool WriteFormulaStartElementWithReference(StyleId? styleId, Def public override bool WriteStartElementWithReference(StyleId styleId, CellWriterState state) => TryWriteCellWithReference(styleId, state); /// - /// Returns false because the value is written together with the end element in . + /// Returns false because the value is written together with the end element. /// public override bool CanWriteValuePieceByPiece(in DataCell cell) => false; public override bool WriteValuePieceByPiece(in DataCell cell, SpreadsheetBuffer buffer, ref int valueIndex) => true; diff --git a/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs index 9c5ccfb6..a631de97 100644 --- a/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs @@ -1,59 +1,68 @@ using SpreadCheetah.CellWriters; using SpreadCheetah.Helpers; +using SpreadCheetah.Styling; +using SpreadCheetah.Styling.Internal; namespace SpreadCheetah.CellValueWriters.Boolean; internal sealed class FalseBooleanCellValueWriter : BooleanCellValueWriter { private static ReadOnlySpan FalseBooleanCell => "0"u8; + private static ReadOnlySpan EndReferenceFalseBooleanValue => "\" t=\"b\">0"u8; private static ReadOnlySpan EndStyleFalseBooleanValue => "\">0"u8; private static ReadOnlySpan EndFormulaFalseBooleanValue => "0"u8; protected override bool TryWriteCell(SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; + return buffer.TryWrite($"{FalseBooleanCell}"); + } + + protected override bool TryWriteCell(StyleId styleId, SpreadsheetBuffer buffer) + { + return buffer.TryWrite($"{BeginStyledBooleanCell}{styleId.Id}{EndStyleFalseBooleanValue}"); + } - if (!FalseBooleanCell.TryCopyTo(bytes, ref written)) return false; + public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) + { + if (styleId is { } style) + { + return buffer.TryWrite( + $"{BeginStyledBooleanCell}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaFalseBooleanValue}"); + } - buffer.Advance(written); - return true; + return buffer.TryWrite($"{BeginBooleanFormulaCell}{formulaText}{EndFormulaFalseBooleanValue}"); } protected override bool TryWriteCellWithReference(CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"b\">0"u8.TryCopyTo(bytes, ref written)) return false; + return state.Buffer.TryWrite($"{state}{EndReferenceFalseBooleanValue}"); + } - buffer.Advance(written); - return true; + protected override bool TryWriteCellWithReference(StyleId styleId, CellWriterState state) + { + return state.Buffer.TryWrite($"{state}{EndReferenceBeginStyled}{styleId.Id}{EndStyleFalseBooleanValue}"); } - protected override bool TryWriteEndStyleValue(Span bytes, out int bytesWritten) + public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { - if (EndStyleFalseBooleanValue.TryCopyTo(bytes)) + if (styleId is { } style) { - bytesWritten = EndStyleFalseBooleanValue.Length; - return true; + return state.Buffer.TryWrite( + $"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaFalseBooleanValue}"); } - bytesWritten = 0; - return false; + return state.Buffer.TryWrite( + $"{state}{EndReferenceBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaFalseBooleanValue}"); } - protected override bool TryWriteEndFormulaValue(Span bytes, out int bytesWritten) + public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) { - if (EndFormulaFalseBooleanValue.TryCopyTo(bytes)) - { - bytesWritten = EndFormulaFalseBooleanValue.Length; - return true; - } - - bytesWritten = 0; - return false; + return cell.Formula is null || buffer.TryWrite($"{EndFormulaFalseBooleanValue}"); } } diff --git a/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs index 30c51347..47573e6e 100644 --- a/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs @@ -1,59 +1,68 @@ using SpreadCheetah.CellWriters; using SpreadCheetah.Helpers; +using SpreadCheetah.Styling; +using SpreadCheetah.Styling.Internal; namespace SpreadCheetah.CellValueWriters.Boolean; internal sealed class TrueBooleanCellValueWriter : BooleanCellValueWriter { private static ReadOnlySpan TrueBooleanCell => "1"u8; + private static ReadOnlySpan EndReferenceTrueBooleanValue => "\" t=\"b\">1"u8; private static ReadOnlySpan EndStyleTrueBooleanValue => "\">1"u8; private static ReadOnlySpan EndFormulaTrueBooleanValue => "1"u8; protected override bool TryWriteCell(SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; + return buffer.TryWrite($"{TrueBooleanCell}"); + } + + protected override bool TryWriteCell(StyleId styleId, SpreadsheetBuffer buffer) + { + return buffer.TryWrite($"{BeginStyledBooleanCell}{styleId.Id}{EndStyleTrueBooleanValue}"); + } - if (!TrueBooleanCell.TryCopyTo(bytes, ref written)) return false; + public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) + { + if (styleId is { } style) + { + return buffer.TryWrite( + $"{BeginStyledBooleanCell}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaTrueBooleanValue}"); + } - buffer.Advance(written); - return true; + return buffer.TryWrite($"{BeginBooleanFormulaCell}{formulaText}{EndFormulaTrueBooleanValue}"); } protected override bool TryWriteCellWithReference(CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"b\">1"u8.TryCopyTo(bytes, ref written)) return false; + return state.Buffer.TryWrite($"{state}{EndReferenceTrueBooleanValue}"); + } - buffer.Advance(written); - return true; + protected override bool TryWriteCellWithReference(StyleId styleId, CellWriterState state) + { + return state.Buffer.TryWrite($"{state}{EndReferenceBeginStyled}{styleId.Id}{EndStyleTrueBooleanValue}"); } - protected override bool TryWriteEndStyleValue(Span bytes, out int bytesWritten) + public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { - if (EndStyleTrueBooleanValue.TryCopyTo(bytes)) + if (styleId is { } style) { - bytesWritten = EndStyleTrueBooleanValue.Length; - return true; + return state.Buffer.TryWrite( + $"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaTrueBooleanValue}"); } - bytesWritten = 0; - return false; + return state.Buffer.TryWrite( + $"{state}{EndReferenceBeginFormula}" + + $"{formulaText}" + + $"{EndFormulaTrueBooleanValue}"); } - protected override bool TryWriteEndFormulaValue(Span bytes, out int bytesWritten) + public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) { - if (EndFormulaTrueBooleanValue.TryCopyTo(bytes)) - { - bytesWritten = EndFormulaTrueBooleanValue.Length; - return true; - } - - bytesWritten = 0; - return false; + return cell.Formula is null || buffer.TryWrite($"{EndFormulaTrueBooleanValue}"); } } From 85194272fab2a133ae1c90fd0594f5768da0b2ac Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 22:27:21 +0100 Subject: [PATCH 18/30] Use SpreadsheetBuffer.TryWrite for string cells --- .../CellValueWriters/StringCellValueWriter.cs | 214 +++++------------- 1 file changed, 53 insertions(+), 161 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs b/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs index 2e91d651..89dd88f3 100644 --- a/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs @@ -11,6 +11,10 @@ internal sealed class StringCellValueWriter : CellValueWriter private static ReadOnlySpan BeginStyledStringCell => " BeginStringFormulaCell => ""u8; private static ReadOnlySpan BeginStyledStringFormulaCell => " EndReferenceBeginString => "\" t=\"inlineStr\">"u8; + private static ReadOnlySpan EndReferenceBeginStyle => "\" t=\"inlineStr\" s=\""u8; + private static ReadOnlySpan EndReferenceBeginFormula => "\" t=\"str\">"u8; + private static ReadOnlySpan EndReferenceBeginFormulaCellStyle => "\" t=\"str\" s=\""u8; private static ReadOnlySpan EndStyleBeginInlineString => "\">"u8; private static ReadOnlySpan EndStringCell => ""u8; @@ -21,221 +25,109 @@ public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyli public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!BeginStyledStringCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!EndStyleBeginInlineString.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(cell.StringValue, bytes, ref written)) return false; - if (!EndStringCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return buffer.TryWrite( + $"{BeginStyledStringCell}{styleId.Id}{EndStyleBeginInlineString}" + + $"{cell.StringValue}" + + $"{EndStringCell}"); } public override bool TryWriteCell(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!BeginStringFormulaCell.TryCopyTo(bytes, ref written)) return false; - } - else + if (styleId is { } style) { - if (!BeginStyledStringFormulaCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; + return buffer.TryWrite( + $"{BeginStyledStringFormulaCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.StringValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); } - if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; - if (!FormulaCellHelper.EndFormulaBeginCachedValue.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(cachedValue.StringValue, bytes, ref written)) return false; - if (!FormulaCellHelper.EndCachedValueEndCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return buffer.TryWrite( + $"{BeginStringFormulaCell}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.StringValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); } public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"inlineStr\">"u8.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(cell.StringValue, bytes, ref written)) return false; - if (!EndStringCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return state.Buffer.TryWrite($"{state}{EndReferenceBeginString}{cell.StringValue}{EndStringCell}"); } public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"inlineStr\" s=\""u8.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!EndStyleBeginInlineString.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(cell.StringValue, bytes, ref written)) return false; - if (!EndStringCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return state.Buffer.TryWrite( + $"{state}{EndReferenceBeginStyle}{styleId.Id}{EndStyleBeginInlineString}" + + $"{cell.StringValue}" + + $"{EndStringCell}"); } public override bool TryWriteCellWithReference(string formulaText, in DataCell cachedValue, StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) + if (styleId is { } style) { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"str\">"u8.TryCopyTo(bytes, ref written)) return false; - } - else - { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"str\" s=\""u8.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; + return state.Buffer.TryWrite( + $"{state}{EndReferenceBeginFormulaCellStyle}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.StringValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); } - if (!SpanHelper.TryWrite(formulaText, bytes, ref written)) return false; - if (!FormulaCellHelper.EndFormulaBeginCachedValue.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(cachedValue.StringValue, bytes, ref written)) return false; - if (!FormulaCellHelper.EndCachedValueEndCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return state.Buffer.TryWrite( + $"{state}{EndReferenceBeginFormula}" + + $"{formulaText}" + + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + + $"{cachedValue.StringValue}" + + $"{FormulaCellHelper.EndCachedValueEndCell}"); } public override bool TryWriteEndElement(SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - if (!EndStringCell.TryCopyTo(bytes)) - return false; - - buffer.Advance(EndStringCell.Length); - return true; + return buffer.TryWrite($"{EndStringCell}"); } public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) { - if (cell.Formula is null) - return TryWriteEndElement(buffer); - - var bytes = buffer.GetSpan(); - if (!FormulaCellHelper.EndCachedValueEndCell.TryCopyTo(bytes)) - return false; - - buffer.Advance(FormulaCellHelper.EndCachedValueEndCell.Length); - return true; + return cell.Formula is null + ? TryWriteEndElement(buffer) + : buffer.TryWrite($"{FormulaCellHelper.EndCachedValueEndCell}"); } public override bool WriteFormulaStartElement(StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!BeginStringFormulaCell.TryCopyTo(bytes, ref written)) return false; - buffer.Advance(written); - return true; - } - - if (!BeginStyledStringCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return styleId is { } style + ? buffer.TryWrite($"{BeginStyledStringCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}") + : buffer.TryWrite($"{BeginStringFormulaCell}"); } public override bool WriteFormulaStartElementWithReference(StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (styleId is null) - { - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"str\">"u8.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; - } - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"inlineStr\" s=\""u8.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!FormulaCellHelper.EndStyleBeginFormula.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return styleId is { } style + ? state.Buffer.TryWrite($"{state}{EndReferenceBeginStyle}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}") + : state.Buffer.TryWrite($"{state}{EndReferenceBeginFormula}"); } public override bool WriteStartElement(SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!BeginStringCell.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return buffer.TryWrite($"{BeginStringCell}"); } public override bool WriteStartElement(StyleId styleId, SpreadsheetBuffer buffer) { - var bytes = buffer.GetSpan(); - var written = 0; - - if (!BeginStyledStringCell.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!EndStyleBeginInlineString.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return buffer.TryWrite($"{BeginStyledStringCell}{styleId.Id}{EndStyleBeginInlineString}"); } public override bool WriteStartElementWithReference(CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"inlineStr\">"u8.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return state.Buffer.TryWrite($"{state}{EndReferenceBeginString}"); } public override bool WriteStartElementWithReference(StyleId styleId, CellWriterState state) { - var buffer = state.Buffer; - var bytes = buffer.GetSpan(); - var written = 0; - - if (!TryWriteCellStartWithReference(state, bytes, ref written)) return false; - if (!"\" t=\"inlineStr\" s=\""u8.TryCopyTo(bytes, ref written)) return false; - if (!SpanHelper.TryWrite(styleId.Id, bytes, ref written)) return false; - if (!EndStyleBeginInlineString.TryCopyTo(bytes, ref written)) return false; - - buffer.Advance(written); - return true; + return state.Buffer.TryWrite($"{state}{EndReferenceBeginStyle}{styleId.Id}{EndStyleBeginInlineString}"); } public override bool CanWriteValuePieceByPiece(in DataCell cell) => true; From f9c42425bda8ab3d74e4c07611a2bbce7c4858ee Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 22:37:43 +0100 Subject: [PATCH 19/30] GetSpan() helper method in string interpolation handler --- SpreadCheetah/SpreadsheetBuffer.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index 9750e658..8f0e8084 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -70,13 +70,15 @@ public TryWriteInterpolatedStringHandler(int literalLength, int formattedCount, _success = true; } + private readonly Span GetSpan() => _buffer._buffer.AsSpan(_buffer._index + _pos); + // TODO: Remove or throw? Literals should rather use ReadOnlySpan [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool AppendLiteral(string value) { if (value is not null) { - var dest = _buffer.GetSpan().Slice(_pos); + var dest = GetSpan(); #if NET8_0_OR_GREATER if (System.Text.Unicode.Utf8.TryWrite(dest, CultureInfo.InvariantCulture, $"{value}", out var bytesWritten)) #else @@ -93,7 +95,7 @@ public bool AppendLiteral(string value) public bool AppendFormatted(int value) { - if (Utf8Formatter.TryFormat(value, _buffer.GetSpan().Slice(_pos), out var bytesWritten)) + if (Utf8Formatter.TryFormat(value, GetSpan(), out var bytesWritten)) { _pos += bytesWritten; return true; @@ -104,7 +106,7 @@ public bool AppendFormatted(int value) public bool AppendFormatted(float value) { - if (Utf8Formatter.TryFormat(value, _buffer.GetSpan().Slice(_pos), out var bytesWritten)) + if (Utf8Formatter.TryFormat(value, GetSpan(), out var bytesWritten)) { _pos += bytesWritten; return true; @@ -115,7 +117,7 @@ public bool AppendFormatted(float value) public bool AppendFormatted(double value) { - if (Utf8Formatter.TryFormat(value, _buffer.GetSpan().Slice(_pos), out var bytesWritten)) + if (Utf8Formatter.TryFormat(value, GetSpan(), out var bytesWritten)) { _pos += bytesWritten; return true; @@ -137,7 +139,7 @@ public bool AppendFormatted(T value) public bool AppendFormatted(string? value) { - if (Utf8Helper.TryGetBytes(value, _buffer.GetSpan().Slice(_pos), out int bytesWritten)) + if (Utf8Helper.TryGetBytes(value, GetSpan(), out int bytesWritten)) { _pos += bytesWritten; return true; @@ -148,7 +150,7 @@ public bool AppendFormatted(string? value) public bool AppendFormatted(scoped ReadOnlySpan utf8Value) { - if (utf8Value.TryCopyTo(_buffer.GetSpan().Slice(_pos))) + if (utf8Value.TryCopyTo(GetSpan())) { _pos += utf8Value.Length; return true; @@ -159,7 +161,7 @@ public bool AppendFormatted(scoped ReadOnlySpan utf8Value) public bool AppendFormatted(CellWriterState state) { - var bytes = _buffer.GetSpan().Slice(_pos); + var bytes = GetSpan(); var bytesWritten = 0; if (!" Date: Tue, 26 Dec 2023 22:48:48 +0100 Subject: [PATCH 20/30] Remove unused method --- SpreadCheetah/CellValueWriters/CellValueWriter.cs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/CellValueWriter.cs b/SpreadCheetah/CellValueWriters/CellValueWriter.cs index 604e4f19..fb367de9 100644 --- a/SpreadCheetah/CellValueWriters/CellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/CellValueWriter.cs @@ -2,7 +2,6 @@ using SpreadCheetah.CellValueWriters.Number; using SpreadCheetah.CellValueWriters.Time; using SpreadCheetah.CellWriters; -using SpreadCheetah.Helpers; using SpreadCheetah.Styling; using SpreadCheetah.Styling.Internal; @@ -36,15 +35,4 @@ internal abstract class CellValueWriter public abstract bool WriteValuePieceByPiece(in DataCell cell, SpreadsheetBuffer buffer, ref int valueIndex); public abstract bool TryWriteEndElement(SpreadsheetBuffer buffer); public abstract bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer); - - protected static bool TryWriteCellStartWithReference(CellWriterState state, Span bytes, ref int bytesWritten) - { - var written = 0; - - if (!" Date: Tue, 26 Dec 2023 23:16:08 +0100 Subject: [PATCH 21/30] More use of SpreadsheetBuffer.TryWrite --- SpreadCheetah/CellWriters/BaseCellWriter.cs | 13 ++----------- SpreadCheetah/MetadataXml/RelationshipsXml.cs | 5 ++--- SpreadCheetah/SpreadsheetBuffer.cs | 11 +++++++++++ 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/SpreadCheetah/CellWriters/BaseCellWriter.cs b/SpreadCheetah/CellWriters/BaseCellWriter.cs index 4673e5a9..7d128e57 100644 --- a/SpreadCheetah/CellWriters/BaseCellWriter.cs +++ b/SpreadCheetah/CellWriters/BaseCellWriter.cs @@ -121,17 +121,8 @@ private bool TryAddRowCellsForList(IList cells) return TryWriteRowEnd(); } - private bool TryWriteRowEnd() - { - var rowEnd = ""u8; - if (rowEnd.TryCopyTo(Buffer.GetSpan())) - { - Buffer.Advance(rowEnd.Length); - return true; - } - - return false; - } + private static ReadOnlySpan RowEnd => ""u8; + private bool TryWriteRowEnd() => Buffer.TryWrite($"{RowEnd}"); private async ValueTask WriteRowEndAsync(Stream stream, CancellationToken token) { diff --git a/SpreadCheetah/MetadataXml/RelationshipsXml.cs b/SpreadCheetah/MetadataXml/RelationshipsXml.cs index de3b787b..5aa00b20 100644 --- a/SpreadCheetah/MetadataXml/RelationshipsXml.cs +++ b/SpreadCheetah/MetadataXml/RelationshipsXml.cs @@ -24,9 +24,8 @@ public static async ValueTask WriteAsync( await using (stream.ConfigureAwait(false)) #endif { - Debug.Assert(Content.Length <= buffer.FreeCapacity); - Content.TryCopyTo(buffer.GetSpan()); - buffer.Advance(Content.Length); + var ok = buffer.TryWrite($"{Content}"); + Debug.Assert(ok); await buffer.FlushToStreamAsync(stream, token).ConfigureAwait(false); } } diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index 8f0e8084..9faef969 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -104,6 +104,17 @@ public bool AppendFormatted(int value) return Fail(); } + public bool AppendFormatted(uint value) + { + if (Utf8Formatter.TryFormat(value, GetSpan(), out var bytesWritten)) + { + _pos += bytesWritten; + return true; + } + + return Fail(); + } + public bool AppendFormatted(float value) { if (Utf8Formatter.TryFormat(value, GetSpan(), out var bytesWritten)) From 30915a06db040e173d002b2db6d4bd15f6d96e88 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 23:25:43 +0100 Subject: [PATCH 22/30] Rename some static ReadOnlySpan --- .../Boolean/BooleanCellValueWriter.cs | 4 ++-- .../Boolean/FalseBooleanCellValueWriter.cs | 4 ++-- .../Boolean/TrueBooleanCellValueWriter.cs | 4 ++-- .../CellValueWriters/NullValueWriterBase.cs | 20 +++++++++---------- .../Number/DoubleCellValueWriter.cs | 12 +++++------ .../Number/FloatCellValueWriter.cs | 12 +++++------ .../Number/IntegerCellValueWriter.cs | 12 +++++------ .../Number/NumberCellValueWriterBase.cs | 14 ++++++------- .../CellValueWriters/StringCellValueWriter.cs | 8 ++++---- .../Time/DateTimeCellValueWriter.cs | 12 +++++------ SpreadCheetah/Helpers/FormulaCellHelper.cs | 2 +- 11 files changed, 52 insertions(+), 52 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Boolean/BooleanCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Boolean/BooleanCellValueWriter.cs index d2ebee4a..3ee759b0 100644 --- a/SpreadCheetah/CellValueWriters/Boolean/BooleanCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Boolean/BooleanCellValueWriter.cs @@ -42,14 +42,14 @@ public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId public override bool WriteFormulaStartElement(StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { return styleId is { } style - ? buffer.TryWrite($"{BeginStyledBooleanCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}") + ? buffer.TryWrite($"{BeginStyledBooleanCell}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}") : buffer.TryWrite($"{BeginBooleanFormulaCell}"); } public override bool WriteFormulaStartElementWithReference(StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { return styleId is { } style - ? state.Buffer.TryWrite($"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}") + ? state.Buffer.TryWrite($"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}") : state.Buffer.TryWrite($"{state}{EndReferenceBeginFormula}"); } diff --git a/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs index a631de97..51d27467 100644 --- a/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs @@ -27,7 +27,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (styleId is { } style) { return buffer.TryWrite( - $"{BeginStyledBooleanCell}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{BeginStyledBooleanCell}{style}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaFalseBooleanValue}"); } @@ -50,7 +50,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c if (styleId is { } style) { return state.Buffer.TryWrite( - $"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaFalseBooleanValue}"); } diff --git a/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs index 47573e6e..264bbcda 100644 --- a/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs @@ -27,7 +27,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (styleId is { } style) { return buffer.TryWrite( - $"{BeginStyledBooleanCell}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{BeginStyledBooleanCell}{style}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaTrueBooleanValue}"); } @@ -50,7 +50,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c if (styleId is { } style) { return state.Buffer.TryWrite( - $"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{EndReferenceBeginStyled}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaTrueBooleanValue}"); } diff --git a/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs b/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs index 8af459c0..d03bc661 100644 --- a/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/NullValueWriterBase.cs @@ -9,7 +9,7 @@ internal abstract class NullValueWriterBase : CellValueWriter protected abstract int GetStyleId(StyleId styleId); private static ReadOnlySpan NullDataCell => ""u8; - private static ReadOnlySpan EndStyleNullValue => "\"/>"u8; // TODO: Rename + private static ReadOnlySpan EndQuoteNullValue => "\"/>"u8; private static ReadOnlySpan EndFormulaEndCell => ""u8; protected static bool TryWriteCell(SpreadsheetBuffer buffer) @@ -19,7 +19,7 @@ protected static bool TryWriteCell(SpreadsheetBuffer buffer) protected static bool TryWriteCell(int styleId, SpreadsheetBuffer buffer) { - return buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{styleId}{EndStyleNullValue}"); + return buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{styleId}{EndQuoteNullValue}"); } protected static bool TryWriteCell(string formulaText, int? styleId, SpreadsheetBuffer buffer) @@ -27,7 +27,7 @@ protected static bool TryWriteCell(string formulaText, int? styleId, Spreadsheet if (styleId is { } style) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaEndCell}"); } @@ -45,7 +45,7 @@ public override bool TryWriteCell(in DataCell cell, StyleId styleId, Spreadsheet protected static bool TryWriteCellWithReference(CellWriterState state) { - return state.Buffer.TryWrite($"{state}{EndStyleNullValue}"); + return state.Buffer.TryWrite($"{state}{EndQuoteNullValue}"); } public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) @@ -55,7 +55,7 @@ public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId protected static bool TryWriteCellWithReference(int styleId, CellWriterState state) { - return state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId}{EndStyleNullValue}"); + return state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId}{EndQuoteNullValue}"); } protected static bool TryWriteCellWithReference(string formulaText, int? styleId, CellWriterState state) @@ -63,13 +63,13 @@ protected static bool TryWriteCellWithReference(string formulaText, int? styleId if (styleId is { } style) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaEndCell}"); } return state.Buffer.TryWrite( - $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaEndCell}"); } @@ -84,15 +84,15 @@ public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) protected static bool WriteFormulaStartElement(int? styleId, SpreadsheetBuffer buffer) { return styleId is { } style - ? buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndStyleBeginFormula}") + ? buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndQuoteBeginFormula}") : buffer.TryWrite($"{FormulaCellHelper.BeginNumberFormulaCell}"); } protected static bool WriteFormulaStartElementWithReference(int? styleId, CellWriterState state) { return styleId is { } style - ? state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndStyleBeginFormula}") - : state.Buffer.TryWrite($"{state}{FormulaCellHelper.EndStyleBeginFormula}"); + ? state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndQuoteBeginFormula}") + : state.Buffer.TryWrite($"{state}{FormulaCellHelper.EndQuoteBeginFormula}"); } public override bool WriteStartElement(SpreadsheetBuffer buffer) => TryWriteCell(buffer); diff --git a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs index e7cf6017..1bf99c7a 100644 --- a/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/DoubleCellValueWriter.cs @@ -15,7 +15,7 @@ public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyli public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndStyleBeginValue}" + + $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndQuoteBeginValue}" + $"{cell.NumberValue.DoubleValue}" + $"{EndDefaultCell}"); } @@ -25,7 +25,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (styleId is { } style) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.DoubleValue}" + @@ -43,7 +43,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { return state.Buffer.TryWrite( - $"{state}{EndStyleBeginValue}" + + $"{state}{EndQuoteBeginValue}" + $"{cell.NumberValue.DoubleValue}" + $"{EndDefaultCell}"); } @@ -51,7 +51,7 @@ public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndStyleBeginValue}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndQuoteBeginValue}" + $"{cell.NumberValue.DoubleValue}" + $"{EndDefaultCell}"); } @@ -61,7 +61,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c if (styleId is { } style) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.DoubleValue}" + @@ -69,7 +69,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c } return state.Buffer.TryWrite( - $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.DoubleValue}" + diff --git a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs index b3731072..69b08ab7 100644 --- a/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/FloatCellValueWriter.cs @@ -15,7 +15,7 @@ public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyli public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndStyleBeginValue}" + + $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndQuoteBeginValue}" + $"{cell.NumberValue.FloatValue}" + $"{EndDefaultCell}"); } @@ -25,7 +25,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (styleId is { } style) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.FloatValue}" + @@ -43,7 +43,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { return state.Buffer.TryWrite( - $"{state}{EndStyleBeginValue}" + + $"{state}{EndQuoteBeginValue}" + $"{cell.NumberValue.FloatValue}" + $"{EndDefaultCell}"); } @@ -51,7 +51,7 @@ public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndStyleBeginValue}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndQuoteBeginValue}" + $"{cell.NumberValue.FloatValue}" + $"{EndDefaultCell}"); } @@ -61,7 +61,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c if (styleId is { } style) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.FloatValue}" + @@ -69,7 +69,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c } return state.Buffer.TryWrite( - $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.FloatValue}" + diff --git a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs index b55d3e45..8f914b0a 100644 --- a/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Number/IntegerCellValueWriter.cs @@ -15,7 +15,7 @@ public override bool TryWriteCell(in DataCell cell, DefaultStyling? defaultStyli public override bool TryWriteCell(in DataCell cell, StyleId styleId, SpreadsheetBuffer buffer) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndStyleBeginValue}" + + $"{StyledCellHelper.BeginStyledNumberCell}{styleId.Id}{EndQuoteBeginValue}" + $"{cell.NumberValue.IntValue}" + $"{EndDefaultCell}"); } @@ -25,7 +25,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (styleId is { } style) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{StyledCellHelper.BeginStyledNumberCell}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.IntValue}" + @@ -43,7 +43,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? defaultStyling, CellWriterState state) { return state.Buffer.TryWrite( - $"{state}{EndStyleBeginValue}" + + $"{state}{EndQuoteBeginValue}" + $"{cell.NumberValue.IntValue}" + $"{EndDefaultCell}"); } @@ -51,7 +51,7 @@ public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? public override bool TryWriteCellWithReference(in DataCell cell, StyleId styleId, CellWriterState state) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndStyleBeginValue}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId.Id}{EndQuoteBeginValue}" + $"{cell.NumberValue.IntValue}" + $"{EndDefaultCell}"); } @@ -61,7 +61,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c if (styleId is { } style) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.IntValue}" + @@ -69,7 +69,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c } return state.Buffer.TryWrite( - $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.IntValue}" + diff --git a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs index 5437b657..b2de20c3 100644 --- a/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs +++ b/SpreadCheetah/CellValueWriters/Number/NumberCellValueWriterBase.cs @@ -9,7 +9,7 @@ internal abstract class NumberCellValueWriterBase : CellValueWriter protected abstract int GetStyleId(StyleId styleId); protected static ReadOnlySpan BeginDataCell => ""u8; - protected static ReadOnlySpan EndStyleBeginValue => "\">"u8; // TODO: Rename + protected static ReadOnlySpan EndQuoteBeginValue => "\">"u8; protected static ReadOnlySpan EndDefaultCell => ""u8; public override bool WriteStartElement(SpreadsheetBuffer buffer) @@ -20,32 +20,32 @@ public override bool WriteStartElement(SpreadsheetBuffer buffer) public override bool WriteStartElement(StyleId styleId, SpreadsheetBuffer buffer) { var style = GetStyleId(styleId); - return buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{EndStyleBeginValue}"); + return buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{EndQuoteBeginValue}"); } public override bool WriteStartElementWithReference(CellWriterState state) { - return state.Buffer.TryWrite($"{state}{EndStyleBeginValue}"); + return state.Buffer.TryWrite($"{state}{EndQuoteBeginValue}"); } public override bool WriteStartElementWithReference(StyleId styleId, CellWriterState state) { var style = GetStyleId(styleId); - return state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{EndStyleBeginValue}"); + return state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{EndQuoteBeginValue}"); } protected static bool WriteFormulaStartElement(int? styleId, SpreadsheetBuffer buffer) { return styleId is { } style - ? buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndStyleBeginFormula}") + ? buffer.TryWrite($"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndQuoteBeginFormula}") : buffer.TryWrite($"{FormulaCellHelper.BeginNumberFormulaCell}"); } protected static bool WriteFormulaStartElementWithReference(int? styleId, CellWriterState state) { return styleId is { } style - ? state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndStyleBeginFormula}") - : state.Buffer.TryWrite($"{state}{FormulaCellHelper.EndStyleBeginFormula}"); + ? state.Buffer.TryWrite($"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndQuoteBeginFormula}") + : state.Buffer.TryWrite($"{state}{FormulaCellHelper.EndQuoteBeginFormula}"); } public override bool CanWriteValuePieceByPiece(in DataCell cell) => true; diff --git a/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs b/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs index 89dd88f3..341029a5 100644 --- a/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/StringCellValueWriter.cs @@ -36,7 +36,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (styleId is { } style) { return buffer.TryWrite( - $"{BeginStyledStringFormulaCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{BeginStyledStringFormulaCell}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.StringValue}" + @@ -69,7 +69,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c if (styleId is { } style) { return state.Buffer.TryWrite( - $"{state}{EndReferenceBeginFormulaCellStyle}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{EndReferenceBeginFormulaCellStyle}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.StringValue}" + @@ -99,14 +99,14 @@ public override bool TryWriteEndElement(in Cell cell, SpreadsheetBuffer buffer) public override bool WriteFormulaStartElement(StyleId? styleId, DefaultStyling? defaultStyling, SpreadsheetBuffer buffer) { return styleId is { } style - ? buffer.TryWrite($"{BeginStyledStringCell}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}") + ? buffer.TryWrite($"{BeginStyledStringCell}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}") : buffer.TryWrite($"{BeginStringFormulaCell}"); } public override bool WriteFormulaStartElementWithReference(StyleId? styleId, DefaultStyling? defaultStyling, CellWriterState state) { return styleId is { } style - ? state.Buffer.TryWrite($"{state}{EndReferenceBeginStyle}{style.Id}{FormulaCellHelper.EndStyleBeginFormula}") + ? state.Buffer.TryWrite($"{state}{EndReferenceBeginStyle}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}") : state.Buffer.TryWrite($"{state}{EndReferenceBeginFormula}"); } diff --git a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs index bfdb370d..f0f73d10 100644 --- a/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Time/DateTimeCellValueWriter.cs @@ -28,7 +28,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (actualStyleId is { } style) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{StyledCellHelper.BeginStyledNumberCell}{style}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.DoubleValue}" + @@ -46,7 +46,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S private static bool TryWriteDateTimeCell(in DataCell cell, int styleId, SpreadsheetBuffer buffer) { return buffer.TryWrite( - $"{StyledCellHelper.BeginStyledNumberCell}{styleId}{EndStyleBeginValue}" + + $"{StyledCellHelper.BeginStyledNumberCell}{styleId}{EndQuoteBeginValue}" + $"{cell.NumberValue.DoubleValue}" + $"{EndDefaultCell}"); } @@ -57,7 +57,7 @@ public override bool TryWriteCellWithReference(in DataCell cell, DefaultStyling? return TryWriteDateTimeCellWithReference(cell, styleId, state); return state.Buffer.TryWrite( - $"{state}{EndStyleBeginValue}" + + $"{state}{EndQuoteBeginValue}" + $"{cell.NumberValue.DoubleValue}" + $"{EndDefaultCell}"); } @@ -73,7 +73,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c if (actualStyleId is { } style) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{style}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.DoubleValue}" + @@ -81,7 +81,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c } return state.Buffer.TryWrite( - $"{state}{FormulaCellHelper.EndStyleBeginFormula}" + + $"{state}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{FormulaCellHelper.EndFormulaBeginCachedValue}" + $"{cachedValue.NumberValue.DoubleValue}" + @@ -91,7 +91,7 @@ public override bool TryWriteCellWithReference(string formulaText, in DataCell c private static bool TryWriteDateTimeCellWithReference(in DataCell cell, int styleId, CellWriterState state) { return state.Buffer.TryWrite( - $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId}{EndStyleBeginValue}" + + $"{state}{StyledCellHelper.EndReferenceBeginStyleId}{styleId}{EndQuoteBeginValue}" + $"{cell.NumberValue.DoubleValue}" + $"{EndDefaultCell}"); } diff --git a/SpreadCheetah/Helpers/FormulaCellHelper.cs b/SpreadCheetah/Helpers/FormulaCellHelper.cs index 295559a8..fbd7c6ea 100644 --- a/SpreadCheetah/Helpers/FormulaCellHelper.cs +++ b/SpreadCheetah/Helpers/FormulaCellHelper.cs @@ -2,7 +2,7 @@ namespace SpreadCheetah.Helpers; internal static class FormulaCellHelper { - public static ReadOnlySpan EndStyleBeginFormula => "\">"u8; // TODO: Rename + public static ReadOnlySpan EndQuoteBeginFormula => "\">"u8; public static ReadOnlySpan BeginNumberFormulaCell => ""u8; public static ReadOnlySpan EndFormulaBeginCachedValue => ""u8; public static ReadOnlySpan EndCachedValueEndCell => ""u8; From 2e8420c6dec4ac4a140318fc2967f808f824d41f Mon Sep 17 00:00:00 2001 From: sveinungf Date: Tue, 26 Dec 2023 23:32:03 +0100 Subject: [PATCH 23/30] Cleanup in SpreadsheetBuffer --- SpreadCheetah/SpreadsheetBuffer.cs | 26 +++++++------------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index 9faef969..81e668a4 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -7,16 +7,11 @@ namespace SpreadCheetah; -internal sealed class SpreadsheetBuffer +internal sealed class SpreadsheetBuffer(byte[] buffer) { - private readonly byte[] _buffer; + private readonly byte[] _buffer = buffer; private int _index; - public SpreadsheetBuffer(byte[] buffer) - { - _buffer = buffer; - } - public Span GetSpan() => _buffer.AsSpan(_index); public int FreeCapacity => _buffer.Length - _index; public void Advance(int bytes) => _index += bytes; @@ -72,22 +67,15 @@ public TryWriteInterpolatedStringHandler(int literalLength, int formattedCount, private readonly Span GetSpan() => _buffer._buffer.AsSpan(_buffer._index + _pos); - // TODO: Remove or throw? Literals should rather use ReadOnlySpan [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool AppendLiteral(string value) { - if (value is not null) + Debug.Fail("Use ReadOnlySpan instead of string literals"); + + if (value is not null && Utf8Helper.TryGetBytes(value, GetSpan(), out var bytesWritten)) { - var dest = GetSpan(); -#if NET8_0_OR_GREATER - if (System.Text.Unicode.Utf8.TryWrite(dest, CultureInfo.InvariantCulture, $"{value}", out var bytesWritten)) -#else - if (Utf8Helper.TryGetBytes(value, dest, out var bytesWritten)) -#endif - { - _pos += bytesWritten; - return true; - } + _pos += bytesWritten; + return true; } return Fail(); From dba02f4a29ddf74cd1abfd4331159ae24ab65b2f Mon Sep 17 00:00:00 2001 From: sveinungf Date: Wed, 27 Dec 2023 00:09:10 +0100 Subject: [PATCH 24/30] Fix style interpolation in boolean writers --- .../CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs | 2 +- .../CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs index 51d27467..df40441e 100644 --- a/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Boolean/FalseBooleanCellValueWriter.cs @@ -27,7 +27,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (styleId is { } style) { return buffer.TryWrite( - $"{BeginStyledBooleanCell}{style}{FormulaCellHelper.EndQuoteBeginFormula}" + + $"{BeginStyledBooleanCell}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaFalseBooleanValue}"); } diff --git a/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs b/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs index 264bbcda..2b37d647 100644 --- a/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs +++ b/SpreadCheetah/CellValueWriters/Boolean/TrueBooleanCellValueWriter.cs @@ -27,7 +27,7 @@ public override bool TryWriteCell(string formulaText, in DataCell cachedValue, S if (styleId is { } style) { return buffer.TryWrite( - $"{BeginStyledBooleanCell}{style}{FormulaCellHelper.EndQuoteBeginFormula}" + + $"{BeginStyledBooleanCell}{style.Id}{FormulaCellHelper.EndQuoteBeginFormula}" + $"{formulaText}" + $"{EndFormulaTrueBooleanValue}"); } From 4a910dad6df623dc795131786849bd8e726c0efc Mon Sep 17 00:00:00 2001 From: sveinungf Date: Wed, 27 Dec 2023 00:11:23 +0100 Subject: [PATCH 25/30] Extend test to cover all cell data types --- .../Tests/SpreadsheetFormulaRowTests.cs | 54 +++++++++---------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/SpreadCheetah.Test/Tests/SpreadsheetFormulaRowTests.cs b/SpreadCheetah.Test/Tests/SpreadsheetFormulaRowTests.cs index 733bc75d..c022ec4d 100644 --- a/SpreadCheetah.Test/Tests/SpreadsheetFormulaRowTests.cs +++ b/SpreadCheetah.Test/Tests/SpreadsheetFormulaRowTests.cs @@ -53,21 +53,19 @@ public async Task Spreadsheet_AddRow_CellWithFormulaAndStyle(bool bold) // Arrange const string formulaText = "SUM(A1,A2)"; using var stream = new MemoryStream(); - await using (var spreadsheet = await Spreadsheet.CreateNewAsync(stream)) - { - await spreadsheet.StartWorksheetAsync("Sheet"); + await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream); + await spreadsheet.StartWorksheetAsync("Sheet"); - var style = new Style(); - style.Font.Bold = bold; - var styleId = spreadsheet.AddStyle(style); + var style = new Style(); + style.Font.Bold = bold; + var styleId = spreadsheet.AddStyle(style); - var formula = new Formula(formulaText); - var cell = new Cell(formula, styleId); + var formula = new Formula(formulaText); + var cell = new Cell(formula, styleId); - // Act - await spreadsheet.AddRowAsync(cell); - await spreadsheet.FinishAsync(); - } + // Act + await spreadsheet.AddRowAsync(cell); + await spreadsheet.FinishAsync(); // Assert SpreadsheetAssert.Valid(stream); @@ -108,30 +106,28 @@ public async Task Spreadsheet_AddRow_CellWithFormulaAndCachedValue(CellValueType Assert.Equal(valueType.GetExpectedDefaultNumberFormat() ?? "", actualCell.Style.NumberFormat.Format); } + public static IEnumerable ItalicWithValueTypes() => TestData.CombineWithValueTypes(true, false); + [Theory] - [InlineData(true)] - [InlineData(false)] - public async Task Spreadsheet_AddRow_CellWithFormulaAndStyleAndCachedValue(bool italic) + [MemberData(nameof(ItalicWithValueTypes))] + public async Task Spreadsheet_AddRow_CellWithFormulaAndStyleAndCachedValue(bool italic, CellValueType cachedValueType, RowCollectionType rowType, bool cachedValueIsNull) { // Arrange const string formulaText = "SUM(A1,A2)"; - const int cachedValue = int.MinValue; using var stream = new MemoryStream(); - await using (var spreadsheet = await Spreadsheet.CreateNewAsync(stream)) - { - await spreadsheet.StartWorksheetAsync("Sheet"); + await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream); + await spreadsheet.StartWorksheetAsync("Sheet"); - var style = new Style(); - style.Font.Italic = italic; - var styleId = spreadsheet.AddStyle(style); + var style = new Style(); + style.Font.Italic = italic; + var styleId = spreadsheet.AddStyle(style); - var formula = new Formula(formulaText); - var cell = new Cell(formula, cachedValue, styleId); + var formula = new Formula(formulaText); + var cell = CellFactory.Create(formula, cachedValueType, cachedValueIsNull, styleId, out var cachedValue); - // Act - await spreadsheet.AddRowAsync(cell); - await spreadsheet.FinishAsync(); - } + // Act + await spreadsheet.AddRowAsync(cell, rowType); + await spreadsheet.FinishAsync(); // Assert SpreadsheetAssert.Valid(stream); @@ -140,7 +136,7 @@ public async Task Spreadsheet_AddRow_CellWithFormulaAndStyleAndCachedValue(bool var actualCell = worksheet.Cell(1, 1); Assert.Equal(formulaText, actualCell.FormulaA1); Assert.Equal(italic, actualCell.Style.Font.Italic); - Assert.Equal(cachedValue, actualCell.CachedValue.GetNumber()); + Assert.Equal(cachedValue.GetExpectedCachedValueAsString(), actualCell.CachedValue.ToString(CultureInfo.InvariantCulture)); } [Theory] From bae4d94b4e84a5a29109498140f0e1f8b2c3cd6b Mon Sep 17 00:00:00 2001 From: sveinungf Date: Wed, 27 Dec 2023 00:38:30 +0100 Subject: [PATCH 26/30] Cover false boolean cells in tests --- SpreadCheetah.Test/Helpers/CellFactory.cs | 12 ++++++------ SpreadCheetah.Test/Helpers/CellValueType.cs | 3 ++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/SpreadCheetah.Test/Helpers/CellFactory.cs b/SpreadCheetah.Test/Helpers/CellFactory.cs index 6a12f669..acf6832b 100644 --- a/SpreadCheetah.Test/Helpers/CellFactory.cs +++ b/SpreadCheetah.Test/Helpers/CellFactory.cs @@ -93,7 +93,8 @@ internal static class CellFactory public static object Create(CellType cellType, CellValueType valueType, bool isNull, StyleId? styleId, out object? value) => valueType switch { - CellValueType.Bool => CreateForBool(cellType, isNull, styleId, out value), + CellValueType.BoolFalse => CreateForBool(cellType, isNull ? null : false, styleId, out value), + CellValueType.BoolTrue => CreateForBool(cellType, isNull ? null : true, styleId, out value), CellValueType.DateTime => CreateForDateTime(cellType, isNull, styleId, out value), CellValueType.Decimal => CreateForDecimal(cellType, isNull, styleId, out value), CellValueType.Double => CreateForDouble(cellType, isNull, styleId, out value), @@ -106,7 +107,8 @@ internal static class CellFactory public static Cell Create(Formula formula, CellValueType valueType, bool isNull, StyleId? styleId, out object? value) => valueType switch { - CellValueType.Bool => CreateForBool(formula, isNull, styleId, out value), + CellValueType.BoolFalse => CreateForBool(formula, isNull ? null : false, styleId, out value), + CellValueType.BoolTrue => CreateForBool(formula, isNull ? null : true, styleId, out value), CellValueType.DateTime => CreateForDateTime(formula, isNull, styleId, out value), CellValueType.Decimal => CreateForDecimal(formula, isNull, styleId, out value), CellValueType.Double => CreateForDouble(formula, isNull, styleId, out value), @@ -117,9 +119,8 @@ internal static class CellFactory _ => throw new ArgumentOutOfRangeException(nameof(valueType), valueType, null) }; - private static object CreateForBool(CellType cellType, bool isNull, StyleId? styleId, out object? value) + private static object CreateForBool(CellType cellType, bool? actualValue, StyleId? styleId, out object? value) { - bool? actualValue = isNull ? null : true; value = actualValue; return cellType switch @@ -131,9 +132,8 @@ private static object CreateForBool(CellType cellType, bool isNull, StyleId? sty }; } - private static Cell CreateForBool(Formula formula, bool isNull, StyleId? styleId, out object? value) + private static Cell CreateForBool(Formula formula, bool? actualValue, StyleId? styleId, out object? value) { - bool? actualValue = !isNull ? true : null; value = actualValue; return new Cell(formula, actualValue, styleId); } diff --git a/SpreadCheetah.Test/Helpers/CellValueType.cs b/SpreadCheetah.Test/Helpers/CellValueType.cs index 40c95158..11760c3d 100644 --- a/SpreadCheetah.Test/Helpers/CellValueType.cs +++ b/SpreadCheetah.Test/Helpers/CellValueType.cs @@ -9,5 +9,6 @@ public enum CellValueType Double, Decimal, DateTime, - Bool + BoolTrue, + BoolFalse } From f9130eabdade757fd3748abe186d7f92b0eedbce Mon Sep 17 00:00:00 2001 From: sveinungf Date: Wed, 27 Dec 2023 01:01:58 +0100 Subject: [PATCH 27/30] Test for DateTime formula cell without the default DateTime style --- SpreadCheetah.Test/Helpers/TestData.cs | 2 +- .../Tests/SpreadsheetFormulaRowTests.cs | 26 +++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/SpreadCheetah.Test/Helpers/TestData.cs b/SpreadCheetah.Test/Helpers/TestData.cs index 8e946996..9b8ec79d 100644 --- a/SpreadCheetah.Test/Helpers/TestData.cs +++ b/SpreadCheetah.Test/Helpers/TestData.cs @@ -5,7 +5,7 @@ namespace SpreadCheetah.Test.Helpers; internal static class TestData { private static readonly CellType[] CellTypeArray = EnumHelper.GetValues(); - private static readonly CellType[] StyledCellTypeArray = new[] { CellType.StyledCell, CellType.Cell }; + private static readonly CellType[] StyledCellTypeArray = [CellType.StyledCell, CellType.Cell]; private static readonly CellValueType[] CellValueTypeArray = EnumHelper.GetValues(); private static readonly RowCollectionType[] RowCollectionTypeArray = EnumHelper.GetValues(); diff --git a/SpreadCheetah.Test/Tests/SpreadsheetFormulaRowTests.cs b/SpreadCheetah.Test/Tests/SpreadsheetFormulaRowTests.cs index c022ec4d..c123ffb7 100644 --- a/SpreadCheetah.Test/Tests/SpreadsheetFormulaRowTests.cs +++ b/SpreadCheetah.Test/Tests/SpreadsheetFormulaRowTests.cs @@ -106,6 +106,32 @@ public async Task Spreadsheet_AddRow_CellWithFormulaAndCachedValue(CellValueType Assert.Equal(valueType.GetExpectedDefaultNumberFormat() ?? "", actualCell.Style.NumberFormat.Format); } + [Fact] + public async Task Spreadsheet_AddRow_CellWithFormulaAndCachedDateTimeValueWithoutDefaultStyle() + { + // Arrange + const string formulaText = "SUM(A1,A2)"; + using var stream = new MemoryStream(); + var options = new SpreadCheetahOptions { DefaultDateTimeFormat = null }; + await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream, options); + await spreadsheet.StartWorksheetAsync("Sheet"); + var formula = new Formula(formulaText); + var cachedValue = new DateTime(2020, 1, 2, 3, 4, 5, DateTimeKind.Utc); + var cell = new Cell(formula, cachedValue); + + // Act + await spreadsheet.AddRowAsync(cell); + await spreadsheet.FinishAsync(); + + // Assert + SpreadsheetAssert.Valid(stream); + using var workbook = new XLWorkbook(stream); + var worksheet = workbook.Worksheets.Single(); + var actualCell = worksheet.Cell(1, 1); + Assert.Equal(formulaText, actualCell.FormulaA1); + Assert.Equal(cachedValue.ToOADate(), actualCell.GetValue(), 0.0001); + } + public static IEnumerable ItalicWithValueTypes() => TestData.CombineWithValueTypes(true, false); [Theory] From c8630a212306ae5f3b8f3d4dfdabb3f415488fd6 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Wed, 27 Dec 2023 01:02:33 +0100 Subject: [PATCH 28/30] Exclude unused methods on string interpolation handler from code coverage --- SpreadCheetah/SpreadsheetBuffer.cs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/SpreadCheetah/SpreadsheetBuffer.cs b/SpreadCheetah/SpreadsheetBuffer.cs index 81e668a4..b7ef0375 100644 --- a/SpreadCheetah/SpreadsheetBuffer.cs +++ b/SpreadCheetah/SpreadsheetBuffer.cs @@ -2,6 +2,7 @@ using SpreadCheetah.Helpers; using System.Buffers.Text; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Runtime.CompilerServices; @@ -67,7 +68,7 @@ public TryWriteInterpolatedStringHandler(int literalLength, int formattedCount, private readonly Span GetSpan() => _buffer._buffer.AsSpan(_buffer._index + _pos); - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [ExcludeFromCodeCoverage] public bool AppendLiteral(string value) { Debug.Fail("Use ReadOnlySpan instead of string literals"); @@ -92,17 +93,6 @@ public bool AppendFormatted(int value) return Fail(); } - public bool AppendFormatted(uint value) - { - if (Utf8Formatter.TryFormat(value, GetSpan(), out var bytesWritten)) - { - _pos += bytesWritten; - return true; - } - - return Fail(); - } - public bool AppendFormatted(float value) { if (Utf8Formatter.TryFormat(value, GetSpan(), out var bytesWritten)) @@ -125,6 +115,7 @@ public bool AppendFormatted(double value) return Fail(); } + [ExcludeFromCodeCoverage] public bool AppendFormatted(T value) { Debug.Fail("Create non-generic overloads to avoid allocations when running on .NET Framework"); From 1934d119c5032e5aeb1e4bb3365221640482bac8 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Wed, 27 Dec 2023 15:13:43 +0100 Subject: [PATCH 29/30] Test for DateTime cell reference with default style --- .../Tests/SpreadsheetRowTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/SpreadCheetah.Test/Tests/SpreadsheetRowTests.cs b/SpreadCheetah.Test/Tests/SpreadsheetRowTests.cs index 5d1b4758..212030d0 100644 --- a/SpreadCheetah.Test/Tests/SpreadsheetRowTests.cs +++ b/SpreadCheetah.Test/Tests/SpreadsheetRowTests.cs @@ -652,6 +652,33 @@ public async Task Spreadsheet_AddRow_ExplicitCellReferencesForLongStringValueCel Assert.Equal(expectedRow1Refs, actualSheet2Refs); } + [Theory] + [InlineData(true)] + [InlineData(false)] + public async Task Spreadsheet_AddRow_ExplicitCellReferenceForDateTimeCellWithDefaultStyling(bool isNull) + { + // Arrange + using var stream = new MemoryStream(); + var options = new SpreadCheetahOptions { WriteCellReferenceAttributes = true }; + await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream, options); + await spreadsheet.StartWorksheetAsync("Sheet1"); + + DateTime? cellValue = isNull ? null : new DateTime(2019, 8, 7, 6, 5, 4, DateTimeKind.Utc); + var cell = new Cell(cellValue); + + // Act + await spreadsheet.AddRowAsync(cell); + await spreadsheet.FinishAsync(); + + // Assert + SpreadsheetAssert.Valid(stream); + using var actual = SpreadsheetDocument.Open(stream, true); + var sheetPart = Assert.Single(actual.WorkbookPart!.WorksheetParts); + var actualRow = Assert.Single(sheetPart.Worksheet.Descendants()); + var actualCell = Assert.Single(actualRow.Descendants()); + Assert.Equal("A1", actualCell.CellReference?.Value); + } + public static IEnumerable RowHeights() => TestData.CombineWithCellTypes( 0.1, 10d, From 876e80e32ece701fb63e848a027ae604b9f2b350 Mon Sep 17 00:00:00 2001 From: sveinungf Date: Wed, 27 Dec 2023 17:56:29 +0100 Subject: [PATCH 30/30] Test for styled cells with long string values --- .../Tests/SpreadsheetStyledRowTests.cs | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/SpreadCheetah.Test/Tests/SpreadsheetStyledRowTests.cs b/SpreadCheetah.Test/Tests/SpreadsheetStyledRowTests.cs index 233b1b56..82ca5da6 100644 --- a/SpreadCheetah.Test/Tests/SpreadsheetStyledRowTests.cs +++ b/SpreadCheetah.Test/Tests/SpreadsheetStyledRowTests.cs @@ -1043,6 +1043,50 @@ public async Task Spreadsheet_AddRow_ExplicitCellReferencesForStyledCells(CellVa Assert.Equal(expectedRow1Refs, actualSheet2Refs); } + [Theory] + [MemberData(nameof(TestData.StyledCellTypes), MemberType = typeof(TestData))] + public async Task Spreadsheet_AddRow_LongStringValueStyledCells(CellType cellType, RowCollectionType rowType) + { + // Arrange + using var stream = new MemoryStream(); + var options = new SpreadCheetahOptions { BufferSize = SpreadCheetahOptions.MinimumBufferSize }; + await using var spreadsheet = await Spreadsheet.CreateNewAsync(stream, options); + var value = new string('a', options.BufferSize * 2); + var style = new Style(); + style.Fill.Color = Color.Thistle; + var styleId = spreadsheet.AddStyle(style); + + var row1 = Enumerable.Range(1, 10).Select(_ => CellFactory.Create(cellType, value, styleId)).ToList(); + var row2 = Enumerable.Range(1, 1).Select(_ => CellFactory.Create(cellType, value, styleId)).ToList(); + var row3 = Enumerable.Range(1, 100).Select(_ => CellFactory.Create(cellType, value, styleId)).ToList(); + + // Act + await spreadsheet.StartWorksheetAsync("Sheet1"); + await spreadsheet.AddRowAsync(row1, rowType); + await spreadsheet.AddRowAsync(row2, rowType); + await spreadsheet.AddRowAsync(row3, rowType); + + await spreadsheet.StartWorksheetAsync("Sheet2"); + await spreadsheet.AddRowAsync(row1, rowType); + + await spreadsheet.FinishAsync(); + + // Assert + SpreadsheetAssert.Valid(stream); + using var actual = SpreadsheetDocument.Open(stream, true); + var sheetParts = actual.WorkbookPart!.WorksheetParts.ToList(); + Assert.Equal(2, sheetParts.Count); + + var sheet1Rows = sheetParts[0].Worksheet.Descendants().ToList(); + Assert.Equal(3, sheet1Rows.Count); + Assert.All(sheet1Rows[0].Descendants(), x => Assert.Equal(value, x.InnerText)); + Assert.All(sheet1Rows[1].Descendants(), x => Assert.Equal(value, x.InnerText)); + Assert.All(sheet1Rows[2].Descendants(), x => Assert.Equal(value, x.InnerText)); + + var sheet2Row = Assert.Single(sheetParts[1].Worksheet.Descendants()); + Assert.All(sheet2Row.Descendants(), x => Assert.Equal(value, x.InnerText)); + } + [Theory] [MemberData(nameof(TestData.StyledCellTypes), MemberType = typeof(TestData))] public async Task Spreadsheet_AddRow_ExplicitCellReferencesForLongStringValueStyledCells(CellType cellType, RowCollectionType rowType)