diff --git a/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.cs b/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.cs
index 0ac1ee2bb234e2..f5c698a1d17e26 100644
--- a/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.cs
+++ b/src/libraries/System.Formats.Cbor/ref/System.Formats.Cbor.cs
@@ -124,7 +124,9 @@ public enum CborTag : ulong
}
public partial class CborWriter
{
- public CborWriter(System.Formats.Cbor.CborConformanceMode conformanceMode = System.Formats.Cbor.CborConformanceMode.Strict, bool convertIndefiniteLengthEncodings = false, bool allowMultipleRootLevelValues = false) { }
+ [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Never)]
+ public CborWriter(System.Formats.Cbor.CborConformanceMode conformanceMode, bool convertIndefiniteLengthEncodings, bool allowMultipleRootLevelValues) { }
+ public CborWriter(System.Formats.Cbor.CborConformanceMode conformanceMode = System.Formats.Cbor.CborConformanceMode.Strict, bool convertIndefiniteLengthEncodings = false, bool allowMultipleRootLevelValues = false, int initialCapacity = -1) { }
public bool AllowMultipleRootLevelValues { get { throw null; } }
public int BytesWritten { get { throw null; } }
public System.Formats.Cbor.CborConformanceMode ConformanceMode { get { throw null; } }
diff --git a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs
index 3f9b25978f23d2..3cbad0bd761d93 100644
--- a/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs
+++ b/src/libraries/System.Formats.Cbor/src/System/Formats/Cbor/Writer/CborWriter.cs
@@ -3,6 +3,7 @@
using System.Buffers;
using System.Collections.Generic;
+using System.ComponentModel;
using System.Diagnostics;
using System.Runtime.InteropServices;
@@ -11,9 +12,10 @@ namespace System.Formats.Cbor
/// A writer for Concise Binary Object Representation (CBOR) encoded data.
public partial class CborWriter
{
+ private const int DefaultCapacitySentinel = -1;
private static readonly ArrayPool s_bufferPool = ArrayPool.Create();
- private byte[] _buffer = null!;
+ private byte[] _buffer;
private int _offset;
private Stack? _nestedDataItems;
@@ -60,7 +62,28 @@ public partial class CborWriter
/// to enable automatically converting indefinite-length encodings into definite-length equivalents and allow use of indefinite-length write APIs in conformance modes that otherwise do not permit it; otherwise, .
/// to allow multiple root-level values to be written by the writer; otherwise, .
/// is not a defined .
- public CborWriter(CborConformanceMode conformanceMode = CborConformanceMode.Strict, bool convertIndefiniteLengthEncodings = false, bool allowMultipleRootLevelValues = false)
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public CborWriter(CborConformanceMode conformanceMode, bool convertIndefiniteLengthEncodings, bool allowMultipleRootLevelValues)
+ : this(conformanceMode, convertIndefiniteLengthEncodings, allowMultipleRootLevelValues, DefaultCapacitySentinel)
+ {
+ }
+
+ /// Initializes a new instance of class using the specified configuration.
+ /// One of the enumeration values that specifies the guidance on the conformance checks performed on the encoded data.
+ /// Defaults to conformance mode.
+ /// to enable automatically converting indefinite-length encodings into definite-length equivalents and allow use of indefinite-length write APIs in conformance modes that otherwise do not permit it; otherwise, .
+ /// to allow multiple root-level values to be written by the writer; otherwise, .
+ /// The initial capacity of the underlying buffer. The value -1 can be used to use the default capacity.
+ ///
+ /// is not a defined .
+ /// -or-
+ /// is not zero, positive, or the default value indicator -1.
+ ///
+ public CborWriter(
+ CborConformanceMode conformanceMode = CborConformanceMode.Strict,
+ bool convertIndefiniteLengthEncodings = false,
+ bool allowMultipleRootLevelValues = false,
+ int initialCapacity = DefaultCapacitySentinel)
{
CborConformanceModeHelpers.Validate(conformanceMode);
@@ -68,6 +91,13 @@ public CborWriter(CborConformanceMode conformanceMode = CborConformanceMode.Stri
ConvertIndefiniteLengthEncodings = convertIndefiniteLengthEncodings;
AllowMultipleRootLevelValues = allowMultipleRootLevelValues;
_definiteLength = allowMultipleRootLevelValues ? null : (int?)1;
+
+ _buffer = initialCapacity switch
+ {
+ DefaultCapacitySentinel or 0 => Array.Empty(),
+ < -1 => throw new ArgumentOutOfRangeException(nameof(initialCapacity)),
+ _ => new byte[initialCapacity],
+ };
}
/// Resets the writer to have no data, without releasing resources.
@@ -205,7 +235,7 @@ private void EnsureWriteCapacity(int pendingCount)
throw new OverflowException();
}
- if (_buffer is null || _buffer.Length - _offset < pendingCount)
+ if (_buffer.Length - _offset < pendingCount)
{
const int BlockSize = 1024;
int blocks = checked(_offset + pendingCount + (BlockSize - 1)) / BlockSize;
diff --git a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.cs b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.cs
index 28faa0ecddc4cd..baf9496266c75f 100644
--- a/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.cs
+++ b/src/libraries/System.Formats.Cbor/tests/Writer/CborWriterTests.cs
@@ -3,6 +3,7 @@
using System.Collections.Generic;
using System.Linq;
+using System.Reflection;
using System.Security.Cryptography;
using Test.Cryptography;
using Xunit;
@@ -332,7 +333,43 @@ public static void WriteEncodedValue_ValidPayloadWithTrailingBytes_ShouldThrowAr
[InlineData((CborConformanceMode)(-1))]
public static void InvalidConformanceMode_ShouldThrowArgumentOutOfRangeException(CborConformanceMode mode)
{
- Assert.Throws(() => new CborWriter(conformanceMode: mode));
+ Assert.Throws("conformanceMode", () => new CborWriter(conformanceMode: mode));
+ }
+
+ [Theory]
+ [InlineData(-2)]
+ [InlineData(int.MinValue)]
+ public static void InvalidInitialCapacity_ShouldThrowArgumentOutOfRangeException(int capacity)
+ {
+ Assert.Throws("initialCapacity", () => new CborWriter(initialCapacity: capacity));
+ }
+
+ [Theory]
+ [InlineData(-1, 0)]
+ [InlineData(0, 0)]
+ [InlineData(1, 1)]
+ [InlineData(1023, 1023)]
+ public static void InitialCapacity_ShouldSetInitialBuffer(int capacity, int expectedBufferLength)
+ {
+ CborWriter writer = new CborWriter(initialCapacity: capacity);
+ byte[]? buffer = (byte[]?)typeof(CborWriter).GetField("_buffer", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(writer);
+
+ Assert.NotNull(buffer);
+ Assert.Equal(expectedBufferLength, buffer.Length);
+ }
+
+ [Theory]
+ [InlineData(0)]
+ [InlineData(-1)]
+ [InlineData(1)]
+ public static void Encode_InitialCapacity_Grows(int capacity)
+ {
+ CborWriter writer = new CborWriter(initialCapacity: capacity);
+ writer.WriteByteString((ReadOnlySpan)new byte[] { 1, 2, 3, 4, 5, 6 });
+ byte[] encoded = writer.Encode();
+
+ ReadOnlySpan expected = new byte[] { (2 << 5) | 6, 1, 2, 3, 4, 5, 6 };
+ AssertExtensions.SequenceEqual(expected, encoded);
}
public static IEnumerable